为什么继承是强耦合的,因为组合在Java中松散耦合?

bra*_*orm 11 java inheritance design-patterns composition

favor composition over inheritance在设计模式中一次又一次地听到这个.引用的一些原因是

1)Inheritance is strongly coupled where as composition is loosely coupled
2) Inheritance is compile time determined where as composition is run-time
3)Inheritance breaks encapsulation where as composition does not
4) anything else I am not aware of
Run Code Online (Sandbox Code Playgroud)

对于像我这样的初学者来说,通过插图来理解遗传和构图在上述方面的不同之处将会很棒.我已经阅读了各种谈论它们的SO链接,但是通过这些关键点的示例对Java初学者来说非常有用.

我认为清楚地理解差异非常重要,而不仅仅是记住要点.

jde*_*dev 7

对于初学者来说这个问题很好,我想我应该首先提醒读者什么是继承和组成,然后继续解释究竟Favor Composition over Inheritance是什么意思.

继承的利弊:

好处:

  • 动态绑定和多态的主要好处之一是它们可以帮助使代码更容易更改.
  • 新的实现很容易,因为大部分都是继承的.修改或扩展重用的实现很容易.

缺点:

  • 打破封装,因为它将子类暴露给
    其超类的实现细节.
  • White-box 重用,因为超类的内部细节通常对子类可见.
  • 如果超类的实现发生更改,则可能必须更改子类.从超类继承的实现无法在运行时更改.

关于这个问题:

当组合松散耦合时,继承是强耦合的

继承会带给你紧耦合,只需对基类进行一次更改就可以打破很多子类.

但是何时使用以及如何检测我们需要继承或组合?
仅在满足以下所有条件时使用继承(Coad规则):

  1. 子类表达is a special kind of而不是表达is a role played by a.
  2. 子类的实例永远不需要成为另一个类的对象.
  3. 子类扩展而不是覆盖或取消其超类的职责.
  4. 子类不会扩展仅仅是实用程序类的功能.
  5. 对于实际问题域中的类,子类专门用于角色,事务或设备.

继承是编译时确定的,其中组合是运行时

编译时,您的基类代码将添加到每个子类.

继承打破了封装,而组合则没有

是.现在你看到了继承的缺点.

底线是:

确保继承模型是is-a关系 我的主要指导思想是只有当子类超类时才应该使用继承.在上面的例子中,Apple很可能是-a Fruit,所以我倾向于使用继承.

当你认为你有一个is-a关系时,问一个自己的一个重要问题是,这是一个关系在整个应用程序的整个生命周期中是不变的,幸运的是,代码的生命周期.例如,你可能认为Employeea-a Person,当真正Employee代表a Person扮演部分时间的角色时.如果这个人失业怎么办?如果这个人既是a Employee又是a Supervisor?这种无常的关系通常应该用构图来建模.

不要仅仅为了获得代码重用而使用继承 如果您真正想要的只是重用代码并且看不到任何关系,请使用组合.

不要仅仅为了获得多态性而使用继承 如果您真正想要的只是多态,但没有自然的is-a关系,请使用带接口的组合.

赞成组合Over Inheritance :)

我直接从javaworld中取得了它.

  • 看起来像是从http://www.javaworld.com/jw-11-1998/jw-11-techniques.html?page=3复制并粘贴的. (2认同)
  • 以我个人的经验,不得不处理遗留的企业源代码,狂热地使用继承进行代码重用,我被阻止在 [溜溜球问题](http://en.wikipedia.org/wiki/Yo-yo_problem), [单元测试几乎是不可能的](http://craigpardey.com/wp/2012/07/anti-pattern-re-use-through-inheritance/),继承案例[刚性](http://www.ifi. uzh.ch/seal/teaching/courses/archive/hs11/reeng/04-OODesignPrinciplesAndViolations.pdf),违反 LSP 是一种已知的 [反模式](http://en.wikipedia.org/wiki/Anti-pattern) (2认同)

duf*_*ymo 3

继承是在代码中使用具体类的扩展来表达的。一旦你编写了它,你就不能在不重写类的情况下更改它。我只能通过修改代码来改变。

public class Foo {
    public void doSomething() { System.out.println("I'm a Foo"); }
}

public class Bar extends Foo {
    public void doSomething() { super.doSomething(); }
}
Run Code Online (Sandbox Code Playgroud)

我只能Bar通过修改一个或两个类来改变它的作用。

组合通常是基于接口的,这意味着您指定完成什么,而不是如何完成。您只需更改接口的实现即可更改方式,而不会影响客户端。

public interface Foo {
    void doSomething();
}

public class FooImpl implements Foo {
    public void doSomething() { System.out.println("I'm a Foo"); }
}

public class Bar implements Foo {
    private Foo foo;

    public Bar(Foo f) { this.foo = f; }

    public void doSomething() { this.foo.doSomething(); }
}
Run Code Online (Sandbox Code Playgroud)

Bar在这种情况下,我可以简单地通过传递接口的不同实现来更改行为Foo

这是鲍勃·马丁的坚实原则之一:开放/封闭原则