3

我知道开放封闭原则意味着开放扩展和封闭修改。考虑如下示例

public class Vehicle{
    public void service(){
        //vehicle servicing code
    }
}

public class Bike extends Vehicle{

    public void service(){
        // bike specific servicing 
    }
}

现在我知道该类使用开放封闭原则Bike扩展并添加了新功能。Vehicle

考虑我创建类的 jar 文件,Vehicle然后Bike类从 jar 扩展Vehicle类。在这种情况下,我们不能修改Vehicle类并Bike扩展它。这是开闭原则的一个很好的例子吗?我想知道OCP与继承有何不同

4

3 回答 3

8

以下是我对解释 OCP 的看法:

OCP 指出,可以根据代码更改的频率对代码进行分类,“相同”代码的各个部分可以有不同的更改频率,我所说的更改不仅是指随时间的变化,而且还包括运行时的变化——例如选择这个或那段特定的代码来执行某些操作。

OCP 要求将更稳定的代码与更可能更改的代码分开。但这并不止于此,它还要求更改频率较低的代码能够与更改频率较高的代码一起工作。

那么OCP ==继承吗?不,继承只是用于实现 OCP 的技术之一。策略模式、装饰器模式、普通组合、参数多态(又名泛型)和其他技术也可以用来实现这些目标。

我所说的不同频率变化的例子。让我们想象一些集合实现。如果每次将一些原始类型添​​加到语言中,集合代码也需要更新,这不是很糟糕吗?因此,集合将它们持有的项目视为不透明的,从而实现了 OCP。下一个示例,让我们从上一个示例中采用相同的集合实现,并假设我们想要打印它的元素排序。简单的。我们只需将排序添加到集合中......以及其他 10 种集合类型?每个新系列也必须实现这种排序?可怕。如果我们的排序算法只是将集合视为不透明类型,如果被要求将连续提供它的项目,那不是更好吗?这是我们排序需要收集的唯一事情,一旦给出元素列表,它可以进行实际排序。行。所以现在集合只需要支持一个串行返回所有项目的操作。简单...如果我们仔细想想,这是一个非常有用的行为,可以用于过滤、转换......

希望通过上面的示例,我展示了一些超越继承的 OCP 用法,并表明 OCP 还鼓励我们将代码视为不同抽象级别的组合(具有不同更改频率的代码组合)。

于 2018-03-12T06:54:38.350 回答
1

OCP 与继承没有什么不同,而是 OCP 的“Open”部分对扩展开放,但对修改应该关闭。即,代码应该只针对错误/错误进行修改,但对于新的扩展或对功能的更改,它应该被扩展。

作为旁注,我相信这会更好地放在programmers.stackexchange.com 网站上。

于 2015-04-07T18:30:58.513 回答
0

问题:没有继承

让我们根据问题中的给定代码构建一个示例。不同的车辆以不同的方式进行维修。因此,我们有不同的类BikeCar因为服务 a 的策略与服务 aBike的策略不同Car

Garage课程接受各种车辆进行维修。观察代码,看看Garage类是如何违反开闭原则的:

class Bike {
    public void service() {
        System.out.println("Bike servicing strategy performed.");
    }
}

class Car {
    public void service() {
        System.out.println("Car servicing strategy performed.");
    }
}

class Garage {
    public void serviceBike(Bike bike) {
        bike.service();
    }

    public void serviceCar(Car car) {
        car.service();
    }
}

Truck正如您可能已经注意到的那样,每当Bus需要维修一些新车时,Garage都需要对其进行修改以定义新方法serviceTruck()serviceBus(). 这意味着Garage班级必须了解所有可能的车辆,例如、BikeCar等。因此,它对修改的开放性违反了开闭原则。此外,它不开放扩展,因为要扩展新功能,我们需要对其进行更改。BusTruck


解决方案:继承

抽象

为了解决上述代码中的问题,满足开闭原则,我们需要抽象出每种车辆的服务策略的实现细节。这意味着我们需要对和类进行抽象。BikeCar

多态性

我们还希望Garage该类接受多种形式的车辆,例如 等BusTruck而不仅仅是BikeCar。这意味着我们需要多态性(多种形式)。

遗产

所以,为了满足开闭原则,最重要的机制是抽象和多态。在 Java、C# 等静态类型语言中,提供抽象和多态性的重要工具是继承

为了抽象出各种类型车辆的服务策略的实现细节,我们使用了一个interface被调用Vehicle并拥有一个抽象方法service()

对于Garage接受多种形式的类Vehicle,我们将其方法的签名更改service(Vehicle vehicle) { }为接受接口Vehicle而不是实际的实现等BikeCar我们还从类中删除了多个方法,因为一个方法将接受多种形式。

interface Vehicle {
    void service();
}

class Bike implements Vehicle {
    @Override
    public void service() {
        System.out.println("Bike servicing strategy performed.");
    }
}

class Car implements Vehicle {
    @Override
    public void service() {
        System.out.println("Car servicing strategy performed.");
    }
}

class Garage {
    public void service(Vehicle vehicle) {
        vehicle.service();
    }
}

关闭进行修改

正如您在上面的代码中看到的那样,现在Garage该类已关闭以进行修改,因为它现在不了解各种类型车辆的服务策略的实现细节,并且可以接受任何类型的 new Vehicle. 我们只需要从Vehicle接口扩展新车辆并将其发送到Garage. 我们不需要更改Garage类中的任何代码。

另一个对修改关闭的实体是我们的Vehicle接口。我们不必更改界面来扩展我们软件的功能。

开放扩展

现在,Garage该类在将支持新类型的上下文中对扩展开放Vehicle,无需修改。

我们的Vehicle接口对扩展是开放的,因为要引入任何新的车辆,我们可以从Vehicle接口扩展并提供一个新的实现以及为该特定车辆提供服务的策略。


所以,正如你所看到的,继承是我们用来遵守开闭原则规则的编程语言提供的一个公正的工具。

就是这样!希望有帮助。

于 2020-10-25T16:29:59.113 回答