从班级继承会在以后伤害你吗?

时间:2010-09-05 15:55:46

标签: c# inheritance oop

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

  • 实现Rectangle-with-hole,我们继承自Rectangle类。在构造函数中,我们检查孔是否在矩形内
  • 后来有人添加了一个新方法Resize to class Rectangle。他们不会检查洞是否仍然在里面。
  • 调整大小后,我们可以使用带有孔的矩形孔,而不是矩形内部,这是一个错误。

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

7 个答案:

答案 0 :(得分:6)

你所描述的是继承的一个陷阱。

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

答案 1 :(得分:5)

对基类的更改可以通过多种方式影响派生类的行为。如果作者突然决定以课程sealed为例,该怎么办?

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

具有继承性的主要“规则”是Liskov Substition Principle。这表明派生类应该可替代基类或从其派生的其他类。

这种情况在它的表面上破坏了这个规则,因为带孔的矩形不是矩形。

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

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

答案 2 :(得分:3)

这称为brittle base class problem

继承的另一个潜在问题通常是您希望使用自己的基类,但框架需要特定的基类(例如ContextBoundObject)而不是接口。

答案 3 :(得分:1)

这就是有先见之明的C#语言设计者将密封关键字添加到语言中的原因。谨慎使用。

使用代码合同来测试不变量,以获得有关破损的早期警告。

答案 4 :(得分:0)

不要在构造函数中调用虚方法。请参阅Eric Lippert关于它的帖子(part 1part 2)。

答案 5 :(得分:0)

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

这可以使用下图实现:alt text

将创建矩形对象并将其包装到HoleDecorator对象中,该对象将负责提供孔。当完成Rectangle的大小调整时,将调用HoleDecorator的Resizing,这将首先调用Rectangle对象的Resize,然后调用Hole装饰器的AddedBehavior,它将指定当主要组件是什么时对孔进行操作。调整大小。

答案 6 :(得分:0)

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

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