理解开闭原则

3

我试图理解开放封闭原则:

模块应该对扩展开放,对修改关闭

就Java而言,扩展是指继承吗?还是包括继承以及添加新方法或属性?

我也很难理解关闭修改,这似乎意味着一旦编写了一个方法,它就不能更改。

这似乎与实际工作相矛盾,因为我会从jira中接手任务,需要在代码库中至少更改一个方法。

在过去的24小时里,我已经阅读了很多帖子和文章,但我仍然不完全确定这个原则想要传达什么。

任何简单的解释都将非常有帮助。


关闭修改意味着改变行为时,您不应该更改类/方法内部的代码。而开放扩展意味着您可以传递不同的参数来改变行为。 - litelite
它确保您不必每次想要向系统添加用例时修改方法以添加逻辑。因为如果您必须这样做,可能会得到一个执行系统所有逻辑的巨大方法。这样的方法是无法维护的(我知道,有经验之谈)。 - litelite
如何通过传递“不同的参数来改变行为”而不更改代码来改变行为?我知道你可以扩展类,但是使用多层继承来实现这一点是否意味着这样做?在Effective Java中,推荐优先使用组合而不是继承。 - berimbolo
@berimblo,你传递了一个具有不同实现的类。你不需要多层继承,只需要像接口一样的一个,它有很多不同的实现。而我所说的是组合。 - litelite
好的,使用接口编程有助于实现这种封闭。 - berimbolo
是的,因为所有可能改变的逻辑都被整洁地封装在一个不需要更改的类中。如果您需要添加功能,只需创建一个实现您接口的新类即可。 - litelite
2个回答

2

你应该写出足够好的代码,不需要修改现有的代码。如果你需要现有方法的功能,应该能够调用该方法,因为它应该具有高内聚性和极低的耦合度。

可以这样想,一旦你建造了一座房子,是尝试将浴室扩大一倍(移动厕所和淋浴重新铺设地板、新墙壁等),还是更容易在房子的前面建造一个阳光房并增加一个新的入口?

你应该尽量避免修改卧室,虽然这并非不可能,但建造一个阳光房会更容易创造新空间。


在你工作/曾经工作的系统中,除了解决错误之外,你从未需要更改方法的行为吗? - berimbolo
我还是不太明白,因为需求和代码都在不断变化。也许这只是我所工作的系统的问题。我现在正在处理的系统有100多名开发人员和10万个用户,因此需求和方法经常发生变化。 - berimbolo
这些原则同样适用于基于Spring的Web应用程序,就像其他任何应用程序一样吗? - berimbolo
我的团队也必须处理高度耦合的代码-这使得新功能非常困难,但遗留代码无处不在。 - Jason V
好的,谢谢。我现在有点更清楚了,似乎很多都与保持方法非常小有关。虽然我们确实有小而离散的方法,但最终某些方法需要包装许多这些调用,我认为开发人员有一种习惯,即在某些地方允许方法变得过于庞大,而不是花时间进行重构。 - berimbolo
显示剩余4条评论

1

开放扩展

模块应该可以合理地进行扩展。如果不能,潜在用户将编写自己的实现,导致重复。

什么是合理的扩展通常是设计中最困难的部分 - 设计者必须预测最终用户需要哪些扩展。

封闭修改

模块的扩展不能破坏模块/声明的功能内部工作。如果模块未能保护其内部工作不被修改,则更难确保(甚至考虑)模块的正确性。基本上,通过允许用户修改您的模块,您正在为您的模块的合同添加一个要求,即扩展不会以破坏它的方式修改您的模块 - 这通常是未记录的要求,并且无法在没有用户对模块的详细了解的情况下实现。


这很容易理解。我更在意的是一旦代码编写完成就不要再修改的原则。例如,数据库映射器会从数据库结果集中获取属性,如果添加了新列,则必须进行更改。同样,映射器利用构建器构建DTO,它们都必须更改以反映新数据库字段的要求。这是扩展吗?看起来是的。现在,对于这种情况,新属性将需要更改传入请求的验证器,在validate()方法中进行逻辑更改。多个代码更改似乎违反了永远不更改代码的原则。 - berimbolo
在上述场景中,显然所有的单元测试和集成测试都将被更改以反映这些变化。 - berimbolo
这个原则对于有被重复使用的野心/可能性的模块非常重要。如果您期望在您的示例中支持两个版本(带有和不带新列),那也是重复使用。否则,这些可能是太小、单一目的的模块,尝试应用该原则可能会导致过于复杂的设计。 - Jiri Tousek
您所说的“重用”,是指作为模块在多个项目中使用吗?我所工作的所有系统都不属于我们,而是客户拥有的,因此我们不倾向于以这种方式编写库,也许这就是为什么没有太多强调这个原则的原因?我们确实使用设计模式和代码接口,因为我们使用Spring。 - berimbolo
该原则特意谈到“模块”,而不是“框架”、“库”、“类”等。它可以应用于任何规模 - 如果您有一个在您(单个)项目中多次重复使用的单个类,则考虑此原则是很好的选择。如果您正在编写将由他人使用的库,则变得更加重要。 - Jiri Tousek
好的,你的回复实际上非常有帮助,感谢你花时间回复。 - berimbolo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接