关于oop:“开放式/封闭式”原则的含义和推理是什么?

What is the meaning and reasoning behind the Open/Closed Principle?

开放/封闭原则指出,软件实体(类,模块等)应为扩展而开放,但为修改而封闭。 这意味着什么,为什么它是良好的面向对象设计的重要原则?


这意味着您应该将新代码放在新的类/模块中。现有代码仅应修改用于错误修复。新类可以通过继承重用现有代码。

开放/封闭原则旨在降低引入新功能时的风险。由于您不修改现有代码,因此可以确保它不会被破坏。它降低了维护成本并提高了产品稳定性。


具体来说,这是有关OOP中设计的"圣杯",即使实体具有足够的可扩展性(通过其单独的设计或通过其参与体系结构)以支持将来无法预见的更改,而无需重写其代码(有时甚至不重新编译) **)。

做到这一点的一些方法包括多态性/继承,组合,控制反转(又称DIP),面向方面的编程,诸如策略的模式,访问者,模板方法以及OOAD的许多其他原理,模式和技术。

**请参见6个"打包原则",REP,CCP,CRP,ADP,SDP,SAP


比DaveK更具体地,它通常意味着,如果要添加其他功能或更改类的功能,请创建一个子类而不是更改原始类。这样,使用父类的任何人都不必担心以后会更改它。基本上,这都是关于向后兼容性的。

面向对象设计的另一个真正重要的原理是通过方法接口的松耦合。如果您要进行的更改不会影响现有界面,那么更改确实很安全。例如,使算法更有效。面向对象的原理也需要通过常识加以调整:)


这是对脆弱的基类问题的解答,该问题认为对基类的看似无害的修改可能会对依赖于先前行为的继承者产生意想不到的后果。因此,您必须谨慎封装不需要的内容,以便派生类遵守基类定义的协定。并且一旦存在继承者,您就必须对在基类中所做的更改非常小心。


Software entities should be open for extension but closed for modification

这意味着任何类或模块都应以可以原样使用,可以扩展但必须修改的方式编写

JavaScript中的错误示例

1
2
3
4
5
6
7
8
9
var juiceTypes = ['Mango','Apple','Lemon'];
function juiceMaker(type){
    if(juiceTypes.indexOf(type)!=-1)
        console.log('Here is your juice, Have a nice day');
    else
        console.log('sorry, Error happned');
}

exports.makeJuice = juiceMaker;

现在,如果要添加其他果汁类型,则必须编辑模块本身。这样,我们就打破了OCP。

Java范例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var juiceTypes = [];
function juiceMaker(type){
    if(juiceTypes.indexOf(type)!=-1)
        console.log('Here is your juice, Have a nice day');
    else
        console.log('sorry, Error happned');
}
function addType(typeName){
    if(juiceTypes.indexOf(typeName)==-1)
        juiceTypes.push(typeName);
}
function removeType(typeName){
  let index = juiceTypes.indexOf(typeName)
    if(index!==-1)
        juiceTypes.splice(index,1);
}

exports.makeJuice = juiceMaker;
exports.addType = addType;
exports.removeType = removeType;

现在,您可以从模块外部添加新的果汁类型,而无需编辑同一模块。


该原理意味着应该轻松添加新功能,而不必更改现有,稳定和经过测试的功能,从而节省了时间和金钱。

通常,多态性(例如使用接口)是实现此目的的好工具。


我只想强调一下,尽管"打开/关闭"在OO编程中显然有用,但它是在开发的所有方面都可以使用的一种健康方法。例如,以我个人的经验,使用纯C时尽可能多地使用"打开/关闭"是一个很好的止痛药。

/罗伯特


符合OCP的另一条经验法则是使基类相对于派生类提供的功能而言是抽象的。或如斯科特·迈耶斯(Scott Meyers)所说,"使非叶子类变得抽象"。

这意味着在基类中具有未实现的方法,并且仅在本身没有子类的类中实现这些方法。然后,由于没有基类的客户,因此不能依赖基类中的特定实现。


开放封闭原则有两种版本。

请参阅以下内容,对两者进行清晰,彻底的解释:https://www.slideshare.net/pjschwarz/first-expedia-tech-know-how-event-the-openclosed-principle-the-original-version-and-当代版本

为了激发您的胃口,以下是前几张幻灯片的屏幕截图:

enter image description here
enter image description here
enter image description here
enter image description here


在设计原则中,SOLID –" SOLID"中的" O"代表打开/关闭原则。

开放封闭原则是一种设计原则,它说一个类,模块和函数应开放以进行扩展,而封闭以进行修改。

该原则指出,代码的设计和编写应采用在不对现有代码(经过测试的代码)进行最小更改的情况下添加新功能的方式进行。设计应以允许将新功能作为新类添加的方式进行,并尽可能使现有代码保持不变。

开放式封闭设计原则的好处:

  • 由于我们不会更改已测试的类,因此应用程序将更强大。
  • 灵活,因为我们可以轻松满足新要求。
  • 易于测试,并且不易出错。
  • 我的博客文章:

    http://javaexplorer03.blogspot.in/2016/12/open-closed-design-principle.html


    最近,我得到了关于该原理含义的另一种想法:开放式封闭原理立即描述了一种编写代码的方式,以及以一种弹性方式编写代码的最终结果。

    我喜欢将"打开/关闭"分为两个紧密相关的部分:

    • 可以更改的代码可以更改其行为以正确处理其输入,也可以进行最少的修改以提供新的使用场景。
    • 如果需要任何人工干预来处理新的使用情况,那么关闭修改的代码并不需要太多。根本不存在这种需求。

    因此,对于显示使用情况超出原始要求的使用情况,表现出"打开/关闭"行为(或者,如果您愿意,则满足"打开/关闭原则")的代码只需进行最少的修改或无需进行任何修改。

    就实施而言?我发现常用的解释是"打开/关闭表示代码是多态的!"充其量只是一个不完整的陈述。代码中的多态性是实现这种行为的一种工具。继承,实现...确实,每种面向对象的设计原则对于编写以该原则所隐含的方式具有弹性的代码都是必需的。


    这意味着应该基于OO软件,但不能进行本质上的更改。这很好,因为它可以确保基类的性能可靠且可预测。


    推荐阅读