开闭原则背后的含义和推理是什么?
-
09-06-2019 - |
题
开放/封闭原则规定软件实体(类、模块等)应该对扩展开放,但对修改关闭。这意味着什么?为什么它是良好的面向对象设计的重要原则?
解决方案
具体来说,它是关于 OOP 中设计的“圣杯”,即使实体具有足够的可扩展性(通过其单独的设计或通过其对架构的参与)以支持未来不可预见的更改,而无需重写其代码(有时甚至无需重新编译) **)。
实现此目的的一些方法包括多态性/继承、组合、控制反转(也称为控制反转)。DIP)、面向方面的编程、策略、访问者、模板方法等模式以及 OOAD 的许多其他原则、模式和技术。
** 参见6条“封装原则”, REP、CCP、CRP、ADP、SDP、SAP
其他提示
这意味着您应该将新代码放入新的类/模块中。现有代码应仅针对错误修复进行修改。新类可以通过继承重用现有代码。
开放/封闭原则旨在降低引入新功能时的风险。由于您不修改现有代码,因此可以放心它不会被破坏。降低维护成本,提高产品稳定性。
这是脆弱基类问题的答案,即对基类看似无害的修改可能会对依赖于先前行为的继承者产生意想不到的后果。因此,您必须小心地封装您不希望依赖的内容,以便派生类将遵守基类定义的契约。一旦继承人存在,你就必须 真的 小心你在基类中所做的更改。
比 DaveK 更具体的是,它通常意味着如果您想要添加附加功能或更改类的功能,请创建一个子类而不是更改原始类。这样,任何使用父类的人都不必担心它以后会发生变化。基本上,这都是关于向后兼容性。
面向对象设计的另一个非常重要的原则是通过方法接口进行松耦合。如果您想要进行的更改不会影响现有界面,那么更改确实非常安全。例如,使算法更加高效。面向对象的原则也需要受到常识的锻炼:)
软件实体应该对扩展开放,对修改关闭
这意味着任何类或模块都应该以可以按原样使用、可以扩展但无需修改的方式编写
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;
现在如果你想添加另一种 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;
现在,您可以从模块外部添加新的果汁类型,而无需编辑同一模块。
该原则意味着可以轻松添加新功能,而无需更改现有的、稳定的和经过测试的功能,从而节省时间和金钱。
通常,多态性(例如使用接口)是实现这一目标的好工具。
符合 OCP 的另一个经验法则是使基类相对于派生类提供的功能进行抽象。或者正如 Scott Meyers 所说的“使非叶类抽象”。
这意味着基类中具有未实现的方法,并且仅在本身没有子类的类中实现这些方法。那么基类的客户端就不能依赖基类中的特定实现,因为基类中没有特定的实现。
我只是想强调,“开放/封闭”虽然在面向对象编程中明显有用,但在开发的各个方面都是一种健康的方法。例如,根据我自己的经验,在使用普通 C 语言时,尽可能多地使用“打开/关闭”是一种很好的止痛药。
/罗伯特
这意味着应该构建面向对象的软件,但不应从本质上进行更改。这很好,因为它确保了基类的可靠、可预测的性能。
最近,我对这一原则的含义有了更多的了解:开闭原则同时描述了一种编写代码的方式,以及以弹性方式编写代码的最终结果。
我喜欢将开放/封闭分为两个密切相关的部分:
- 代码是 打开 更改可以更改其行为以正确处理其输入,或者需要最小的修改来提供新的使用场景。
- 代码是 关闭 修改不需要太多(如果有的话)人工干预来处理新的使用场景。这种需求根本不存在。
因此,表现出开放/封闭行为(或者,如果您愿意,满足开放/封闭原则)的代码需要很少的修改或不需要修改,以响应超出其最初构建目的的使用场景。
至于实施方面?我发现常见的解释是:“开/封闭是指代码是多态的!”充其量是一个不完整的声明。代码中的多态性是实现这种行为的一种工具。继承、实现……实际上,每一个面向对象的设计原则对于编写按照该原则所暗示的方式具有弹性的代码都是必要的。
在设计原则中,SOLID——“SOLID”中的“O”代表开/闭原则。
开闭原则是一种设计原则,它规定类、模块和函数应该对扩展开放,对修改封闭。
该原则指出,代码的设计和编写应以在现有代码(经过测试的代码)中进行最少更改的情况下添加新功能的方式完成。设计的方式应该允许添加新功能作为新类,并尽可能保持现有代码不变。
开闭式设计原则的好处:
- 应用程序将更加健壮,因为我们不会更改已经测试过的类。
- 灵活是因为我们可以轻松适应新的要求。
- 易于测试且不易出错。
我的博客文章对此进行了阐述:
http://javaexplorer03.blogspot.in/2016/12/open-close-design-principle.html