开放/封闭原则背后的含义和推理是什么?

问题描述 投票:39回答:11

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

oop definition solid-principles design-principles open-closed-principle
11个回答
23
投票

具体来说,它是关于OOP中设计的“圣杯”,即使实体可扩展(通过其个人设计或通过其参与架构)来支持未来不可更改的更改而无需重写其代码(有时甚至无需重新编译**)。

一些方法包括多态性/继承,组合,控制反转(a.k.a.DIP),面向方面编程,模式,如策略,访客,模板方法,以及OOAD的许多其他原则,模式和技术。

**参见6“包装原则”,REP, CCP, CRP, ADP, SDP, SAP


0
投票

最近我对这个原则的含义有了额外的了解:开放 - 封闭原则立即描述了编写代码的方式,以及以弹性方式编写代码的最终结果。

我想将Open / Closed拆分为两个密切相关的部分:

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

因此,展示开放/封闭行为的代码(或者,如果您愿意,满足开放/封闭原则)需要最少的修改或不修改以响应超出最初构建的使用场景。

就实施而言?我发现通常所说的解释,“打开/关闭是指代码是多态的!”至多是一个不完整的陈述。代码中的多态性是实现这种行为的一种工具;继承,实现......实际上,每个面向对象的设计原则都是编写具有弹性的代码所必需的。


0
投票

在设计原则中,SOLID - “SOLID”中的“O”代表开/关原理。

开放封闭原则是一种设计原则,它表示类,模块和功能应该是开放的,但是可以关闭以进行修改。

这个原则规定代码的设计和编写应该以一种新的功能添加方式完成,只需对现有代码(测试代码)进行最小的更改。设计应该以允许添加新功能作为新类的方式完成,尽可能保持现有代码不变。

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

  1. 应用程序将更加健壮,因为我们没有更改已经测试过的类。
  2. 灵活,因为我们可以轻松满足新的要求。
  3. 易于测试,不易出错。

我的博客文章:

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


39
投票

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

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


5
投票

这是脆弱的基类问题的答案,它说对基类的看似无辜的修改可能会对依赖于先前行为的继承者产生意想不到的后果。因此,您必须小心地封装您不想依赖的内容,以便派生类将遵循基类定义的契约。一旦存在继承者,你必须非常小心你在基类中改变了什么。


5
投票

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

面向对象设计的另一个非常重要的原则是通过方法接口的松散耦合。如果您要进行的更改不会影响现有界面,则更改非常安全。例如,使算法更有效。面向对象的原则也需要通过常识来缓和:)


5
投票

软件实体应开放以进行扩展,但已关闭以进行修改

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

Javascript中的错误示例

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;

现在,如果你想添加Another Juice类型,你必须编辑模块本身,通过这种方式,我们打破了OCP。

Javascript中的好例子

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;

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


2
投票

该原则意味着它可以轻松添加新功能,而无需更改现有的,稳定的和经过测试的功能,从而节省时间和金钱。

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


1
投票

符合OCP的另一个经验法则是根据派生类提供的功能使基类抽象化。或者正如Scott Meyers所说'Make Non-leaf classes abstract'。

这意味着在基类中具有未实现的方法,并且只在没有子类的类中实现这些方法。然后基类的客户端不能依赖基类中的特定实现,因为没有。


1
投票

我只想强调“开放/封闭”即使在OO编程中明显有用,也是一种在开发的各个方面都使用的健康方法。例如,根据我自己的经验,使用普通C时尽可能多地使用“打开/关闭”是一个很好的止痛药。

/罗伯特·


0
投票

这意味着OO软件应该建立在本质上,而不是内在地改变。这很好,因为它确保了基类的可靠,可预测的性能。

© www.soinside.com 2019 - 2024. All rights reserved.