开闭原则

5
我知道这个原则是说一个模块应该对扩展开放,对修改关闭。当我们想要升级/修改某个类中的方法时,就需要创建另一个继承基类的类,并在此处覆盖基本方法以保留两个功能。
但是如果我们想要向基类添加另一个不同的方法呢?这是否被视为基类的修改或扩展 - 向基类添加方法是否可以,还是我们也应该创建一个继承基类的新类,然后将新方法放在那里?
同样,对于向基类添加属性和字段,是否适用相同的问题。

2
有没有选项可以对接口进行修改呢?回答你的问题 - 我认为那是一种更改而不是扩展。至于方法,您考虑过扩展方法吗?它们按定义是扩展原始功能的。 - Konrad Viltersten
2
开闭原则的真正含义是,当您想要向一个过程添加更多功能时,您不应该改变原始过程。 - Callum Linington
@Konrad Viltersten 我可能错了,但我认为扩展方法仅在您想要扩展不属于您的类的功能时才是首选。 - Ivan
1
我理解的OCP如下:您的系统应该被设计成这样,如果您想要扩展它,您应该编写新代码而不是重写旧代码。 - Dmitry Pavlushin
是的,它确实只与基类相关,这也是我犹豫的主要原因。我想将其放在基类中以符合单一职责原则。 - Ivan
显示剩余4条评论
1个回答

6
TL;DR 我认为添加一个新方法本质上意味着你不能违反OCP; 因为OCP主要关注现有方法的鲁莽重写。
示例:基类Calculator被MyCustomCalculator继承。基类只有用于两个数字相加、相减、相乘和相除的方法。 在MyCustomCalculator中创建一个新方法,例如CalculateAverage(params int[])不会违反OCP。它不会修改任何现有方法的逻辑,它只是扩展了计算器对象所提供的方法。
新方法本质上不会改变旧方法。因此,它们不会修改现有逻辑;它们只是扩展了可用的内容。
所以,它(本质上)不违反OCP。
它很难违反OCP,因为创建新内容与修改现有内容(本质上)完全不同。
需要注意以下几点: - 我可以想到一个(有争议的)例外情况:重载。如果创建一个重载现有方法的新方法,则必须遵守重载规则。最重要的是,这意味着重载方法应执行与彼此完全相同的任务(重载方法仅基于不同的输入参数,但它们的处理和输出应是功能等价的)。虽然我不确定这是否违反了OCP(因为它错误地扩展了基类),还是SRP(因为它创建了关于重载方法的处理/输出的模棱两可的责任)。看起来有点像两者兼而有之。 - 即使您的新方法没有重载现有方法,相同的原则也适用。新方法是否足够相关以承担基类的责任(意图/目的)?因为如果非常不同,则可能会违反SRP。
编辑 这取决于上下文。对于我提供的Calculator / MyCustomCalculator / CalculateAverage()示例;我本能地将其添加到基类中,因为计算平均值是与计算器的职责相关的基本操作。
但是,如果我们讨论添加一个仅涉及复数的方法(MethodForComplexNumbers()),那么我会主张创建一个从Calculator继承并实现MethodForComplexNumbers()的ComplexNumberCalculator。
然而,我认为主要是由于SRP,而不是OCP。

值得讨论一些边角情况:例如,如果一个类涉及任何形式的(反)序列化,那么向该类添加内容就足以破坏现有的序列化数据。 - grek40
@grek40: 你确定吗?因为数据反序列化应该只尝试设置在序列化数据中找到的属性。只要这些属性仍然存在于类中,它就不应该关心您添加的其他属性。特别是由于序列化需要一个无参数构造函数,任何未被设置的属性应该已经有可行的默认值。(此外,通常情况下,SOLID原则在边缘案例下会失效。它是一个好的指南,但不是一个很好的全局性法则)。 - Flater
@grek40:我唯一看到的问题是序列化 updated 类,然后尝试使用 outdated 版本进行反序列化。但这是一个固有的无法避免的问题,除非采用一些过度的 try/catch 逻辑(我不赞成这种做法)。 - Flater
一个有良好习惯的序列化器应该会忽略额外的数据...但即使C#比其他语言少了一些陷阱,仍然存在像二进制格式化程序这样的东西,需要您满足它们的特殊需求,以避免破坏事物。正如所说,这是一个边角情况,而不是主要使用场景。另一个更常见的例子:考虑一个带有自动生成列的UI表-通过将附加属性扩展到数据项类中,UI将发生变化。 - grek40
任何更改都是一种权衡,可能会与反射相结合产生副作用 - 最终开发人员必须决定这些事情是否是实际问题。如果没有任何限制,声称扩展不是关键的一般规则将是无效的。 - grek40
@grek40:我并不是说你错了(二进制序列化是一个很好的例子),但它似乎超出了SOLID所关注的范围。SOLID对现有保存的数据没有影响。SOLID只关注合理的良好实践。我从未见过任何一个项目(除了小例子)完全遵循SOLID原则到吹毛求疵的程度。你会发现,一旦实施的努力超出了所获得的收益,就不再值得这样做了。 - Flater

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