我知道开放式封闭原则意味着对扩展开放并且关闭以进行修改。考虑一个例子如下
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与继承的区别
答案 0 :(得分:2)
以下是我对口译OCP的看法:
OCP指出代码可以根据其变化的频率进行分类,“相同”代码的各个部分可以具有不同的变化频率,并且通过变化,我的意思不仅是随时间变化而且还意味着运行时间的变化 - 例如选择这段或那段特定的代码来执行某些操作。
OCP要求将更稳定的代码与更可能更改的代码分开。但它并不止于此,而是要求不经常更改的代码能够更频繁地改变代码。
OCP ==继承也是如此?否。继承只是用于实现OCP的技术之一。策略模式,装饰模式,普通组合,参数多态(又名泛型)以及其他技术也可用于实现这些目标。
我所说的不同变化频率的例子。让我们来看一些集合实现。难道不是很糟糕,如果每次将某种原始类型添加到语言中,集合代码也需要更新吗?因此,集合将它们持有的项目视为不透明,从而实现OCP。下一个例子。让我们从前面的例子中获取相同的集合实现,并想象我们想要打印它的元素排序。简单。我们只是为一个集合....和其他10个集合类型添加排序?每个新系列都必须实现那种类型吗?可怕。如果我们的排序算法只是将集合视为不透明类型,如果被要求将连续提供它的项目,那不是更好吗?这是我们的排序需要收集的唯一事情,并且一旦给出元素列表,它就可以进行实际排序。好。所以现在集合只需要支持连续返回所有项目的操作。容易......如果我们考虑一下,它可以用于过滤,转换,它是非常有用的行为....
希望通过上面的例子我展示了继承之外的一些OCP用法,并且表明OCP还鼓励我们将我们的代码视为不同抽象层次的组合(具有不同变化频率的代码组合)。
答案 1 :(得分:1)
OCP与继承没有区别,而OCP的“开放”部分是开放的,但应该关闭进行修改。 即代码应仅针对错误/错误进行修改,但对于新扩展或更改应扩展的功能。
作为旁注,我相信最好放在programmers.stackexchange.com网站上。
答案 2 :(得分:0)
让我们根据问题中的给定代码构建示例。不同的车辆以不同的方式维修。因此,我们为Bike
和Car
使用了不同的类,因为服务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();
}
}
您可能已经注意到,每当要维修诸如Truck
或Bus
之类的新车时,都需要修改Garage
来定义新方法serviceTruck()
和serviceBus()
。这意味着Garage
类必须知道所有可能的车辆,例如Bike
,Car
,Bus
,Truck
等。因此,它因开放修改而违反了开闭原则。另外,它也无法扩展,因为要扩展新功能,我们需要对其进行更改。
抽象
要解决上述代码中的问题并满足开闭原则,我们需要为每种类型的车辆提取维修策略的实施细节。这意味着我们需要Bike
和Car
类的抽象。
多态
我们还希望Garage
类接受车辆的许多形式,例如Bus
,Truck
等,而不仅仅是{{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
接口进行扩展,并提供一种新的实施方案以及为该特定车辆提供维修服务的策略。
因此,如您所见,继承是我们用来遵守开放原则原则的编程语言提供的一种公正工具。
就是这样!希望有帮助。