Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,为什么继承是强耦合的,而as组合是松散耦合的?_Java_Design Patterns_Inheritance_Composition - Fatal编程技术网

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

在Java中,为什么继承是强耦合的,而as组合是松散耦合的?,java,design-patterns,inheritance,composition,Java,Design Patterns,Inheritance,Composition,我在设计模式中一再听到这样的说法:组合优于继承。其中一些原因如下: 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)

我在设计模式中一再听到这样的说法:组合优于继承。其中一些原因如下:

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初学者来说,浏览这些关键点的示例会很好


我认为清楚地理解差异比仅仅记住要点更为重要。

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

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
的行为

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(); }
}

这是Bob Martin的原则之一:。

对于初学者来说,这是一个好问题,也是一个大问题,我想我应该首先提醒读者什么是继承和组合,然后继续解释
支持组合而不是继承的确切含义。

继承的利弊

优势:

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

  • 中断封装,因为它将子类公开给实现
    其超级类的详细信息
  • 白盒
    重用,因为超类的内部细节通常是 对子类可见
  • 如果 超类改变。继承自超类的实现可以 不能在运行时更改
关于这个问题:

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

继承将带来紧密耦合,只需对基类进行一次更改,就可以中断许多子类。

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

  • 子类表示
    是一种特殊的
    ,而非
    是由
    扮演的角色
  • 子类的实例永远不需要成为另一个类的对象
  • 子类扩展而不是重写或取消 它是超一流的
  • 子类不会扩展仅仅是一个类的功能 实用类
  • 对于实际问题域中的类,子类专门 角色、事务或设备
  • 继承是编译时确定的,其中as composition是运行时的

    编译时,基类代码将添加到每个子类中

    继承会破坏封装,而as组合不会

    对。现在您看到了继承的缺点

    底线是

    确保继承为is-a关系建模 我的主要指导思想是,只有在子类是超类时才应该使用继承。在上面的例子中,
    Apple
    很可能是-a
    水果
    ,因此我倾向于使用继承

    当您认为自己拥有is-a关系时,需要问自己的一个重要问题是,该is-a关系是否会在应用程序的整个生命周期以及代码的整个生命周期中保持不变。例如,您可能会认为
    员工
    是一个
    ,而实际上
    员工
    代表一个
    在一定时间内扮演的角色。如果这个人失业了怎么办?如果此人既是
    员工
    又是
    主管
    ,该怎么办?这种无常的is-a关系通常应该用合成来建模

    不要仅仅为了代码重用而使用继承 如果您真正想要的只是重用代码,而眼前并没有关系,那么就使用组合

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

    偏好组合而非继承:)


    我直接引用了。

    上面的几个编号项目将受益于包含“可能”或“可能是”这两个短语。将优雅地回答问题。即使使用接口,实现接口的类也必须实现接口的方法,这涉及到重写实现类中的实现..?合成是否必须使用接口?你不能使用一个具体的
    类吗?
    ?基于接口是最好的,IMO.IMO你应该对delegation.OP发表评论,除非你设计了一个组合框架,否则你必须更改代码。在这种情况下,对象的组成将完全基于数据,但您将受限于您正在使用/编写的框架。看起来您是从中复制和粘贴的。这是一个一般性问题,我尝试一步一步地解释。我尝试帮助您。是的,答案的一部分只是复制和过去。根据我个人的经验,必须处理遗留的企业源代码,狂热地使用继承进行代码重用,我被阻止了,继承被阻止了,违反LSP是众所周知的