更新代表实际值的常数是否违反开放式原则?


10

我有一堂课计算工人的年净收入。它有一个代表税率百分比的常数。但是有一天,税率发生了变化,因此我需要修复代码。

固定该常数的行为是否表示违反了“ 开放-封闭原则”,因为它假定应该关闭类进行修改?


10
软件的变化是因为现实世界的变化。另一方面,将税率设为常数并不会违反开放式封闭原则,而只是做一个无知的事情。税率是一个明显的可变项,应在运行时绑定。
理查德·钱伯斯

4
我完全同意理查德的观点。如果您必须更改代码以解决此“常量”问题,则OCP最少会出现问题。
罗伯特·哈维

3
构成违反OCP的行为是高度主观的,无论如何,整个过程还是有些过时的(因为实现继承不再是最佳实践)。这是一个典型的问题,您必须猜测提出该问题的人的想法。
罗伯特·布劳蒂加姆(RobertBräutigam),

2
@DocBrown:什么构成“新要求”?您向我展示了一些代码,我可以指出一些新的要求,这些要求肯定需要更改代码,而不管您如何使OCP符合要求。回到问题所在:如果开发人员向业务专家询问此问题,并且没有期望税率每两年更改一次以上,那么就没有必要使它可配置或可注入。只要保持简单,为您所知道的做准备。对于这些事情,可以肯定的是,将其置于课堂之外。因此要看情况
罗伯特·布劳蒂加姆(RobertBräutigam),

1
@RobertBräutigam:我的意思是,恕我直言,没有“ OCP符合”之类的东西,只有“在某些类别的要求的上下文中符合OCP”。当然,组件应符合“ OCP符合”类别的主观性。但是,在我所理解的这个问题所描述的情况下,已经确定了一个变化的要求,因此,在这种特定要求的背景下,这种“收入计算类别”显然不服从OCP。
布朗

Answers:


14

考虑供应商A在某种黑盒库中供用户B,C和D使用的类或组件时,可以更好地理解OCP(请注意,这只是我为了清楚起见而使用的一种思维模型,实际上,该类的唯一用户是否是A自己都没有关系。

如果B,C和D可以在不同用例中使用或重用提供的类,而无需修改库的源代码,则该组件将满足OCP(就用例类别而言)。有多种方法可以实现这一目标,例如

  • 使类可继承(通常与模板方法模式或策略模式结合使用)

  • 通过为依赖项注入提供“注入点”

  • 通过为类或组件提供配置参数(例如,根据您的情况,使用构造函数参数“ tax percent”,或使用其他配置机制)

  • 可能还有其他方法,具体取决于编程语言或生态系统

您在教科书中找到的典型示例通常是第一类或第二类(我想是因为在那些书的作者看来,第三类太过琐碎,值得一提)。

如您所见,这与供应商A禁止对源代码进行任何更改(例如,错误修复,优化或以向后兼容的方式添加新功能)无关,这与OCP完全无关。OCP是关于A如何设计库中组件的接口和粒度的,因此不同的重用场景(例如使用不同税率的重用)不会自动引起变更需求。

因此,尽管这里有人告诉您,答案显然是“是”,但这违反了OCP。

编辑:似乎在某人之间写了一篇关于该主题的详细博客文章。尽管它的某些部分本来可以用更好的措词来表达(如Derek Elkins所指出的那样),但似乎作者通常同意我的观点,即“实现OCP”不是绝对的,而是只能在某些情况下进行评估。需求变更的类别。


好的,因此OCP即将使用您列出的三种方式之一为不同的用例提供可扩展的行为,对吗?但是,如果OP的示例暗示基本面即将发生变化,该怎么办?我不知道哪个国家/地区的OP来自哪个国家/地区,但是在我的国家/地区,税率变化不大。这是一个糟糕的例子,但也许是有意地将其提取为常数,以强调这一点。我很确定它不是可配置或可扩展的。因此,也许问题在于“这与供应商A禁止对源代码的任何更改无关”。
Vadim Samokhin

至少我是这样理解的。可怜的人删除了他接受的答案,所以我猜也是。您从另一个角度看过它-我理解您的观点并同意。但似乎最明智的评论是@RobertBräutigam。到目前为止,我还没有意识到OCP是主观的。
Vadim Samokhin

1
我想如果有人问过同样的问题,我应该回答一个问题:“该行为是否应该以某种方式扩展或配置?”。如果是,那么直接修改类本身就是对OCP的违反。如果否,则OCP根本不适用这种情况。
Vadim Samokhin

1
@Zapadlo:我认为某个组件是否满足OCP 的一类要求不是很主观-在大多数情况下,很明显新的需求是否需要修改组件的源代码,或者该组件是否支持该要求”可能的办法来实现它不限于前3个手段我上市,看到我的编辑自己的主体性概念可能会导致因为OCP只是有一个误导性的名称,是非常糟糕的许多教科书的解释。
文件布朗

我的主观性观念是由于我不完全理解您所说的话而引起的-但我想我现在就知道了。非常感谢您的深刻见解和您的回答。
Vadim Samokhin

4

就像其他人说的那样,理想情况下,工人收入类别应允许常数的参数化,使该类别独立于该值。

最终,调用应用程序还可能允许根据外部配置(例如文件)进行参数化。进行外部配置后,我们可以更改税率-尽管请注意,如果在启动时仅读取配置文件一次,则必须重新启动应用程序才能使更新的税率生效,因此请注意心神。我们可以提供一种应用程序功能,可以在需要时重新读取配置,或者可以提供一种更复杂的机制来通知配置文件何时更改...

从长远来看,您可能会发现税收问题不仅需要一个百分比,例如,一天的税法更加复杂,并且需要几个百分比和一些常数(例如,不足1万美元的金额应按X%征税,而其余部分按Y%征税)。

基本上,这建议使用一种策略模式,其中此处涉及的主类接受用于计算税金的策略对象。

可以从配置文件中选择各种策略(以及%和$常量),现在,添加新策略需要添加一些新代码,但不一定要更新现有代码。

每个策略都可能知道如何解析/解释自己的外部配置参数,以及如何计算实际税金。

从动态上讲,税收可能进一步取决于管理区域设置,因此您可能将区域设置与收入或与雇员(或两者)相关联。在外部配置中,我们可能会将语言环境与税收策略相关联。


另请参阅依赖注入,在这里我们明确地管理这些事情。


1
问题不是在代码中埋入税率之类的东西是否不是一个坏主意,我相信这对我们大多数人(包括OP)都是显而易见的。问题是,“这是否违反了OCP?” 因此,我看不出您的答案是如何提到这个问题的。
布朗

1

如果您需要修改类别以更改税额,则其设计确实违反了OCP。到目前为止,您所描述的适当设计是使计算器类将税金值作为参数。

如果您的类是实例化的(意味着它不是静态类),则通过使tax变量class属性(其值是通过构造函数注入)来改善类的内聚性的。

简而言之,您当前的设计使您的类依赖于不是真正常数的常数值(将常数定义为无论如何都不会改变的值,例如PI的值)。它违反了OCP。更改设计以将税额作为构造函数参数接收。


0

完全同意@Becuzz,我只想总结一下:OCP是关于查找注入到类中的重用(因此有用)抽象的。因此,该类的行为不是通过更改其代码而是通过为其提供不同的实现来修改的。罗伯特·马丁(Robert Martin)的书“ 敏捷软件开发,原理,模式和实践 ”中明确指出了这一点,并选中了相应的章节“开放式原则”,“抽象是关键”子章节。它澄清了另一个误解,即只能通过继承来修改行为。是Bertrand Meyer在1988年的《面向对象的软件构造》一书中提出了这一建议,而不是Robert Martin。


-2

我的看法并不违反开放封闭原则。但是,必须随时间变化的某些事物(例如税率)是一个常数这一事实是设计缺陷:您不应更改常数的值,而应更改税率的处理方式。这应该是可以在不重新编译整个内容的情况下进行修改的某种类型的设置。


“设计缺陷”是它违反了开放封闭原则,因为您需要重新编译代码以更改常量?
埃德里克·艾诺罗斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.