使用继承作为重用代码的方法有什么缺点?

时间:2010-07-20 21:04:01

标签: inheritance code-reuse

使用继承作为重用代码的方法有哪些缺点?

5 个答案:

答案 0 :(得分:6)

IIRC, Liskov替代原则 1) 假定一个人应该能够用任何派生类;也就是说,派生类的行为不应与其基类的行为完全不同,或违反其基类的合同。

显然,这个原则对一个(基类)类如何被另一个类(从它派生)“重用”有意限。其他使用类的方法,例如聚合或组合,不受此原则的限制。


1)参见例如The Liskov Substitution Principle(链接到PDF文档)。

答案 1 :(得分:6)

使用继承来实现代码重用会遇到以下问题:

  1. 您无法在运行时更改重用的行为。继承是编译时依赖项,因此如果GameClient类继承自TCPSocket以重用connect()write()成员函数,则它具有硬编码的TCP功能。您无法在运行时更改此内容。

  2. 为了进行测试,您无法从外部替换重用的行为。如果GameClient类继承自TCPSocket以使其获得write()(用于将数据写入套接字),则无法从外部交换此代码。您无法插入另一个write()函数,该函数会记录GameClient想要写入文件的所有数据。

  3. 除了最简单的应用程序之外,您依赖于多重继承。这为diamond shaped inheritance trees打开了大门,这大大增加了代码的复杂性。

  4. 优先使用继承的组合来重用代码可以避免所有这些问题。

答案 2 :(得分:3)

使用继承意味着当您在同一个类中调用方法(或C ++中的虚方法)时,您可能实际上无法实际调用子类的方法。可能导致的代码气味是一个在类层次结构中上下移动的调用堆栈,这实际上意味着您的超类和子类处于循环依赖中。

使用组合和接口清楚地表明存在多个可能的实现,并且当存在循环依赖(通常应该被删除)时也很明显。

(由于几个原因,组合使循环依赖显而易见(假设您通过构造函数使用类的传递依赖关系)。如果A和B相互依赖,则A构造B并传递this或者self进入B的构造函数,这是循环依赖的明显标志,或者其他一些类构造A和B,结果证明是不可能的,因为A要求首先构造B,B要求A为首先构建。)

答案 3 :(得分:0)

它需要继承(反思它),这只是代码的许多可能结构之一。这就是为什么我们有程序编程,函数编程,面向对象编程,面向方面编程,声明性编程等等。参见programming paradigms

答案 4 :(得分:0)

如果使用继承,则会陷入可变状态面向对象的范例。如果您尝试使用不可变对象,则最终会编写[pseudocode]

class A (int X, int Y)
    def self.nextX(int nextX) = A(newX, self.Y)

class B (int X, int Y, int Z) extends A(X, Y)
    def self.nextX(int nextX) = B(newX, self.Y, self.Z)

并且没有代码重用。因此,你使用可变对象,然后疯狂:)。