假设我有以下设计代码:
abstract class Root
{
public abstract void PrintHierarchy();
}
class Level1 : Root
{
override public void PrintHierarchy()
{
Console.WriteLine("Level1 is a child of Root");
}
}
class Level2 : Level1
{
override public void PrintHierarchy()
{
Console.WriteLine("Level2 is a child of Level1");
base.PrintHierarchy();
}
}
如果我只查看Level2
类,我可以立即看到Level2.PrintHierarchy
跟在the open/closed principle之后,因为它自己做了一些事情并调用了基础方法,它覆盖了Level1
但是,如果我只查看base.PrintHierarchy
类,它似乎违反了OCP,因为它没有调用Level1
- 实际上,在C#中,编译器禁止它错误“无法调用抽象基础成员”。
使Root.PrintHierarchy
看起来遵循OCP的唯一方法是将PrintHierarchy
更改为空的虚方法,但是我不能再依赖编译器来强制派生类来实现{{1 }}
我在维护代码时遇到的真正问题是看到几十个不调用override
的{{1}}方法。如果base.Whatever()
是抽象的,那么很好,但如果没有,那么base.Whatever
方法可能是被拉入接口的候选者而不是具体的可覆盖方法 - 或类或方法需要以某种方式进行重构,但不管怎样,它都清楚地表明设计不佳。
如果没有记住Whatever
是抽象的或在Root.PrintHierarchy
内添加评论,我是否还有其他选项可以快速确定类似Level1.PrintHierarchy
的类是否违反了OCP?
评论中有很多很好的讨论,也有一些很好的答案。我无法弄清楚到底要问什么。我觉得让我感到沮丧的是,as @Jon Hanna points out,有时虚拟方法只是表示“你必须实现我”,而有时候它意味着“你必须扩展我 - 如果你没有调用基础版本,你就会打破我的设计!”但是C#没有提供任何方式来表明你的意思,除了那个抽象或界面显然是一个“必须实现”的情况。 (除非代码合同中有某些内容,我认为这有点超出范围)。
但是如果一个语言 有一个必须实现与必须扩展的装饰器,如果它不能被禁用,它可能会为单元测试带来巨大的问题。有这样的语言吗?这听起来很像design-by-contract,所以如果它出现在埃菲尔,我也不会感到惊讶。
最终结果可能是as @Jordão says,而且完全是上下文的;但在我接受任何答案之前,我将暂时搁置讨论。
答案 0 :(得分:5)
Root
定义以下内容:Root对象具有PrintHierarchy方法。它没有定义关于PrintHierarchy方法的更多信息。
Level1
有一个PrintHierarchy方法。它不会停止使用PrintHierarchy方法,因此它不会违反开放/封闭原则。
现在,更重要的是:将“PrintHierarchy”重命名为“Foo”。 Level2是否遵循或违反开放/封闭原则?
答案是我们没有线索,因为我们不知道“Foo”的语义是什么。因此,我们不知道是否应该在方法体的其余部分之后,在休息之前,在其中间或根本不调用base.Foo。
1.ToString()
应该返回“System.ObjectSystem.ValueType1”还是“1System.ValueTypeSystem.Object”以保持打开/关闭时的假装,或者应该将base.ToString()
的调用分配给未使用的变量在返回“1”之前?
显然没有这些。它应尽可能返回有意义的字符串。它的基类型尽可能地返回有意义的字符串,并且扩展不会因调用它的基础而受益。
打开/关闭原则意味着当我调用Foo()时,我希望发生一些Fooing,并且当我在Level1上调用它时我期望一些Level1适当的Fooing,而当我在Level2上调用它时,我期望一些Level2适当的Fooing。 Level2 Fooing是否应该涉及一些Level1 Fooing也会发生取决于Fooing是什么。
base
是一种帮助我们扩展课程的工具,而不是一项要求。
答案 1 :(得分:3)
无法决定系统(或类)是否通过静态查看系统(或类),而没有上下文信息。
只有当知道 可能对设计的更改时,才能判断它是否遵循OCP进行这些特定类型的更改。
没有可以帮助你的语言结构。
一个好的启发式方法是使用某种指标,例如罗伯特·马丁的instability and abstractness (pdf),或指导缺乏凝聚力的指标,以更好地为更改系统做好准备,并拥有更好的遵循OCP的机会以及OOD的所有其他重要原则。
答案 2 :(得分:1)
OCP是关于先决条件和后置条件的:“当你只能用较弱的一个取代它的前提条件,而用一个较强的条件替换它的后置条件”。 我不认为在重写方法中调用base会违反它。