开放原则与继承之间的区别

时间:2015-04-07 17:54:12

标签: inheritance open-closed-principle

我知道开放式封闭原则意味着对扩展开放并且关闭以进行修改。考虑一个例子如下

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

public class Bike extends Vehicle{

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

现在我了解Bike类已扩展Vehicle并使用Open Closed Principle添加新功能。

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

3 个答案:

答案 0 :(得分:2)

以下是我对口译OCP的看法:

OCP指出代码可以根据其变化的频率进行分类,“相同”代码的各个部分可以具有不同的变化频率,并且通过变化,我的意思不仅是随时间变化而且还意味着运行时间的变化 - 例如选择这段或那段特定的代码来执行某些操作。

OCP要求将更稳定的代码与更可能更改的代码分开。但它并不止于此,而是要求不经常更改的代码能够更频繁地改变代码。

OCP ==继承也是如此?否。继承只是用于实现OCP的技术之一。策略模式,装饰模式,普通组合,参数多态(又名泛型)以及其他技术也可用于实现这些目标。

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

希望通过上面的例子我展示了继承之外的一些OCP用法,并且表明OCP还鼓励我们将我们的代码视为不同抽象层次的组合(具有不同变化频率的代码组合)。

答案 1 :(得分:1)

OCP与继承没有区别,而OCP的“开放”部分是开放的,但应该关闭进行修改。 即代码应仅针对错误/错误进行修改,但对于新扩展或更改应扩展的功能。

作为旁注,我相信最好放在programmers.stackexchange.com网站上。

答案 2 :(得分:0)

问题:没有继承

让我们根据问题中的给定代码构建示例。不同的车辆以不同的方式维修。因此,我们为BikeCar使用了不同的类,因为服务Bike的策略不同于服务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();
    }
}

您可能已经注意到,每当要维修诸如TruckBus之类的新车时,都需要修改Garage来定义新方法serviceTruck()serviceBus()。这意味着Garage类必须知道所有可能的车辆,例如BikeCarBusTruck等。因此,它因开放修改而违反了开闭原则。另外,它也无法扩展,因为要扩展新功能,我们需要对其进行更改。


解决方案:具有继承性

抽象

要解决上述代码中的问题并满足开闭原则,我们需要为每种类型的车辆提取维修策略的实施细节。这意味着我们需要BikeCar类的抽象

多态

我们还希望Garage类接受车辆的许多形式,例如BusTruck等,而不仅仅是{{1} }和Bike。这意味着我们需要多态性(许多形式)。

继承

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

要为各种类型的车辆抽象维修策略的实施细节,我们使用称为Car的{​​{1}}并具有抽象方法interface

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

Bike

已关闭修改

您可以在上面的代码中看到,Car类现在已关闭以进行修改,因为它现在不知道各种车辆的维修策略的实现细节,并且可以接受任何类型的车辆新的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界面扩展新的载具并将其发送到Vehicle。我们不需要更改Vehicle类中的任何代码。

另一个无法修改的实体是我们的Garage接口。 我们不必更改界面即可扩展软件的功能。

开放扩展

Garage类现在可以在不需要修改的情况下支持新的Vehicle类型,因此可以扩展。

我们的Garage接口是开放的,因为要引入任何新的车辆,我们可以从Vehicle接口进行扩展,并提供一种新的实施方案以及为该特定车辆提供维修服务的策略。


因此,如您所见,继承是我们用来遵守开放原则原则的编程语言提供的一种公正工具。

就是这样!希望有帮助。