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

在设计模式中,我一次又一次地听到了这种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 

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

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

对于初学者来说这个问题很好,我认为我应该首先提醒inheritance和构成,然后去解释究竟什么才是最重要的。

散文和inheritance权

优点:

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

缺点:

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

关于这个问题:

当组合松散耦合时,inheritance是强耦合的

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

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

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

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

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

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

是的。看看inheritance的缺点。

底线是

确保inheritance模型是is-a关系我的主要指导思想是只有当子类是超类时才应该使用inheritance。 在上面的例子中,Apple可能是一个Fruit,所以我倾向于使用inheritance。 当你认为你有一个is-a关系时,问一个自己的一个重要问题是,这是一个关系在整个应用程序的整个生命周期中是不变的,幸运的是,代码的生命周期。 例如,您可能认为Employee是一个Person,而真正的Employee代表Person在部分时间内扮演的角色。 如果这个人失业怎么办? 如果此人既是员工又是主管怎么办? 这种无常的关系通常应该用构图来建模。

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

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

赞成组合Over Inheritance 🙂

我从javaworld直接拿了它。

inheritance在代码中使用extends表示具体类。 一旦你编写它,你就不能在不重写类的情况下改变它。 我只能通过修改代码来改变。

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

我只能通过修改一个或两个类来改变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(); } } 

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

这是Bob Martin的SOLID原则之一: 开放/封闭原则 。