2010-09-05 140 views
7

当我们从一个类继承时,它可以提供场景吗?它可以工作一段时间,但是其他的东西会改变并引入一个错误? 我想出了以下情况:从一个班级继承以后会伤害你吗?

  • 实现矩形有孔,我们从类Rectangle继承。在构造函数中,我们检查该洞是否在矩形内
  • 稍后有人添加一个Resize类到Rectangle的新方法。他们不检查洞是否仍在里面。
  • 经过调整大小后,我们可以在带矩形孔的矩形孔中出现,这是一个错误。

如果我选择在C#中使用对象继承,我应该小心哪些其他问题。

+1

在C#中不需要小心,在任何面向对象的语言中都要小心。基类应该永远不必担心它们的后代。 – Robaticus 2010-09-05 16:11:29

+0

@Robaticus:我说C#是因为在C++中我们可以继承多个类,并且更容易陷入困境。在C#中,我们只能从一个类继承。 – 2010-09-05 16:19:58

+0

我仍然支持我说的话。无论使用哪种语言,都应该注意这一点。它不是C#独有的。 – Robaticus 2010-09-05 18:19:32

回答

5

对基类的改变会影响派生类的行为有很多种方法。如果作者突然决定例如使类sealed怎么办?

像任何界面一样,如果消费者不需要修改,它需要保持稳定。

继承的主要“规则”是Liskov替换原则。这表明派生类应该可以替代基类或从它派生的其他类。

这种情况下,它的表面会破坏这条规则,因为带孔的矩形不是矩形。

通常最好使用接口将行为划分为合理的可实现块。这种界面通常用形容词而不是名词来命名。例如,矩形和带有孔的矩形都可以被渲染,所以接口可能是IRenderable。如果它可以调整大小,你可能会有一个IResizable等等。这些可以汇总到一个IShape,但是你要小心你的Shape定义只定义了问题域中的行为。

直接从另一个类派生可能会非常危险,因为您受到该类行为的约束。如果您真的需要这样做,最好将您需要的实现提取到一个公共基类中(例如Rectangle : RectangleImplementation, IShape)。

6

你所描述的是继承的缺陷之一。

另一个缺陷是深层继承层次结构。在composition over inheritance上的Stackoverflow线程。

+0

希望我可以投这更多。 – 2010-09-05 16:05:52

0

不要在构造函数中调用虚方法。查看Eric Lippert的帖子(part 1part 2)。

3

这就是众所周知的brittle base class problem

与一般的继承另一个潜在的问题是,当你想用你自己的基本类,但一个框架需要特定的基类(例如,ContextBoundObject),而不是一个接口。

1

这就是为什么预测性的C#语言设计师将密封关键字添加到该语言。明智地使用。

并使用代码合约来测试您的不变式以获得有关破损的早期警告。

+0

Hans,你用什么来表示“使用代码契约来测试你的不变式以获得关于破坏的早期警告”? – 2010-09-05 17:08:10

+0

链接:http://devjourney.com/blog/code-contracts-part-4-object-invariants/ – 2010-09-05 17:20:04

+0

不错的链接,谢谢! – 2010-09-05 20:28:03

0

在这些类型的案例中更好地使用-Decorator模式。 这提供了更好的扩展方式。

这可以通过使用下面的图来实现:alt text

矩形对象将被创建并包裹成HoleDecorator对象,这将是负责提供的孔中。当完成Rectangle的大小调整时,将调用HoleDecorator的调整大小,这将首先调用Rectangle对象的Resize,然后调用Hole Decorator的AddedBehavior,它将指定当主要组件是调整大小。

+0

可以指定如何实现带矩形的矩形? – 2010-09-05 17:10:47

0

我认为这与c#或继承无关。无论你做什么,这都是软件开发的必然问题。

最好的和简单的解决方案是每天构建您的代码并执行unit testing

+0

我们总是使用单元测试和配置项,但我不明白在这种情况下如何提供帮助。我们不针对尚不存在的情况创建单元测试。在开发之前,我们不可能有单元测试预测Resize方法。你能建议它是如何发生的吗? – 2010-09-06 00:30:56

+0

单元测试通常会调用方法并比较输入和输出。我正在做类似问题的基于场景的单元测试。用你的榜样;在创建了矩形后,将对象传递给Rectangle测试(执行调整大小,移动等)测试,并将其传递给具有相同上下文的Rectangle-With-Hole测试(执行边界检查)。这完全取决于开发人员的愿景,而不是完美的,但有时比方法测试更好。顺便说一句,它不是取代方法测试,它只是一个附加测试。 – ertan 2010-09-06 19:05:31

相关问题