开源库中OCP的好例子

Dan*_*Dan 6 oop open-closed-principle solid-principles

关于stackoverflow的"开放封闭原则"主题已经有很多讨论.然而,似乎通常对该原理的更宽松的解释是普遍的,因此例如Eclipse可以通过插件进行修改.

根据严格的OCP,您应该修改原始代码只是为了修复错误,而不是添加新的行为.

在公共或OS库中是否有任何严格解释OCP的好例子,你可以通过OCP观察一个特征的演变:有一个类Foo,方法是bar(),而且还有一个FooDoingAlsoX和foo2()方法.库的下一个版本,其中原始类已被扩展,其中原始代码未被修改.

编辑:根据Robert C. Martin的说法:"模块的二进制可执行版本,无论是可链接库,DLL还是Java .jar都保持不变"*.我从未看到库保持关闭,实际上新的行为被添加到库中并且新版本已发布.根据OCP,新行为属于新的二进制模块.

*Robert C. Martin的敏捷软件开发,原则,模式和实践

Mar*_*ius 3

OCP 原则规定,类应当对扩展开放,但对更改关闭。实现这一点的关键是抽象。如果你还读过 DIP 原理,你会发现抽象不应该依赖于细节,而细节应该依赖于抽象。在您的示例中,您的界面中有详细信息(两个特定方法 bar() 和 foo2())。要完全实现 OCP,您应尽量避免此类细节(例如,尝试将它们移至抽象后面,而采用一种具有不同实现的通用 foo 方法)。

例如,看一下 SolrNet 中的这个接口: https://github.com/mausch/SolrNet/blob/master/SolrNet/ISolrCommand.cs 这是一个通用命令,仅表明可以执行命令,但它并不不提供更多细节。

细节在于接口的实现: https://github.com/mausch/SolrNet/tree/master/SolrNet/Commands

正如您所看到的,您可以添加任意数量的命令,而无需更改任何其他类的实现。具体实现可以被认为是封闭的修改,但接口允许我们用新命令扩展功能,并且特此开放扩展。

(无论如何,SolrNet 并不是特别出色,我只是使用了这个项目中的示例,因为当我阅读这篇文章时,我的浏览器中恰好有它,几乎所有良好编码的 OO 项目都以某种方式利用了 OCP 原则)

编辑:如果您想要二进制级别的示例,您可以查看 nopCommerce (http://nopcommerce.codeplex.com/releases/view/69081),例如您可以在其中添加自己的运输提供商、付款方式提供商或汇率提供商,甚至无需通过实现一组接口来触及原始 DLL。再说一遍,这对于 nopCommerce 来说并不是什么特别的事情,这只是我想到的第一个项目,因为我几天前使用过它;)

OCP 并不是一个只能在二进制级别上使用的原则,好的 OOD 使用 OCP,不是在任何地方,而是在所有适合的级别中使用;)二进制级别上的“严格”OCP 并不总是合适,并且会添加一个如果您在每种情况下都使用它,那么它会带来额外的复杂性,当您想要在运行时更改实现或当您希望让外部开发人员能够扩展您的接口时,它最有趣。在设计界面时,您应始终牢记 OCP 原则,但不应将其视为法律,而应将其视为应在正确情况下使用的原则。

我想当您引用 Robert C Martin 时,您指的是敏捷原则、模式和实践,如果是这样,请阅读同一章中的结论,他所说的内容与我上面所做的相同。例如,如果您阅读他的《Clean Code》一书,他对 OCP 原理给出了更详细的解释,我想说上面的引用有点不幸,因为它会让人们认为您应该始终将新代码放入新的 DLL:s、JAR 中:s 或 libs,事实是您应始终考虑上下文。

我认为你应该看看 Martins 关于 OCP 的最新白皮书http://objectmentor.com/resources/articles/ocp.pdf(他也在他后来的书《Clean Code》中提到过),他从来没有提到过为了分隔二进制文件,他指的是“类、模块、函数”。我认为这证明了 Martin 在谈论 OCP 时不仅指的是二进制扩展,还指的是类和函数的扩展,因此二进制扩展并不比我第一个示例中的类扩展更“严格”。