【发布时间】:2010-10-07 16:42:06
【问题描述】:
假设我有以下人为的代码:
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类,它似乎违反了OCP,因为它没有调用base.PrintHierarchy——实际上,在C#中,编译器禁止它并显示错误“无法调用一个抽象基成员”。
使Level1 看起来遵循OCP 的唯一方法是将Root.PrintHierarchy 更改为空的虚拟方法,但是我不能再依赖编译器强制派生类来实现PrintHierarchy。
我在这里维护代码时遇到的真正问题是看到几十个override 方法不调用base.Whatever()。如果base.Whatever 是抽象的,那么很好,但如果不是,那么Whatever 方法可能是被拉入接口而不是具体的可覆盖方法的候选方法——或者需要重构类或方法其他一些时尚,但无论哪种方式,它都清楚地表明设计不佳。
没有记住 Root.PrintHierarchy 是抽象的或在 Level1.PrintHierarchy 中添加评论,我是否有任何其他选择可以快速确定像 Level1 这样形成的类是否违反 OCP?
在 cmets 中有很多很好的讨论,也有一些很好的答案。我很难弄清楚到底要在这里问什么。我认为让我感到沮丧的是,as @Jon Hanna points out,有时一个虚拟方法只是表示“你必须实现我”,而其他时候它意味着“你必须扩展我——如果你没有调用基本版本,你就会破坏我的设计!”但是 C# 没有提供任何方法来指示您的意思,除了抽象或接口显然是“必须实现”的情况。 (除非代码合同中有一些东西,我认为这有点超出了范围)。
但是如果一种语言确实有一个必须实现与必须扩展的装饰器,如果它不能被禁用,它可能会给单元测试带来巨大的问题。有没有类似的语言?这听起来很像design-by-contract,所以如果它在埃菲尔,我不会感到惊讶。
最终结果可能是as @Jordão says,它完全是上下文相关的;但在我接受任何答案之前,我将让讨论开放一段时间。
【问题讨论】:
-
您在寻找静态分析工具吗?如果是,那么也许这可能会有所帮助stackoverflow.com/q/1627024/119477
-
我认为重点(和问题)是您无法判断仅通过查看
Level1的Level1是否违反了OCP实现:你不知道它的base是抽象的。 (因此“如果base.Whatever是抽象的,那么很好。”) -
-
@Jeff,您无法判断通过查看是否调用了
base,Level2 也没有违反 OCP。我们可能会在适当时使用base来帮助坚持它,但如果它不适合方法的目的,那么这样做可能是错误的。 -
@Mark,我想知道对 OCP 的关注是否分散了我认为是您的核心问题的注意力,我将其总结为“虚拟方法(与抽象方法相对)是否有任何在好的设计中扮演什么角色?”
标签: c# oop open-closed-principle