组合
组合关系概述
- 实现类的复用除了继承外,还可以使用
组合
的方式,把该类当成另一个类的组合成分
,从而允许新类直接复用该类的public方法
。 - 不管继承还是组合,都允许在新类(对于继承就是子类)中直接复用旧类的方法。
- 组合是把
旧类对象作为新类的成员变量
组合起来,用以实现新类的功能
,用户看到的是新类的方法,而不能看到被组合对象的方法。因此,通常要在新类里使用private修饰被组合的旧类对象
。
组合和继承
从类的复用角度看,父类的功能等同于组合中被组合的类,都将自身的方法提供给新类使用;子类和组合关系里的整体类,都可复用原有类的方法,用于实现自身的功能。
继承关系中从多个子类抽象出共有父类的过程,类似于组合关系中多个整体类里提取被组合类的过程;继承关系中从父类派生子类的过程,则类似于组合关系中被组合类组合到整体类的过程。
使用继承实现:
class Animal { private void beat() { System.out.println("心脏跳动..."); } public void breath() { beat(); System.out.println("吸一口气,吐一口气,呼吸中..."); } } // 继承Animal,直接复用父类的breath()方法 class Bird extends Animal { public void fly() { System.out.println("我在天空自在的飞翔..."); } } // 继承Animal,直接复用父类的breath()方法 class Wolf extends Animal { public void run() { System.out.println("我在陆地上的快速奔跑..."); } } public class InheritTest { public static void main(String[] args) { Bird b = new Bird(); b.breath(); b.fly(); Wolf w = new Wolf(); w.breath(); w.run(); } }
上述继承关系也可以使用组合实现:
class Animal { private void beat() { System.out.println("心脏跳动..."); } public void breath() { beat(); System.out.println("吸一口气,吐一口气,呼吸中..."); } } class Bird { // 将原来的父类组合到原来的子类,作为子类的一个组合成分 private Animal a; public Bird(Animal a) { this.a = a; } // 重新定义一个自己的breath()方法 public void breath() { // 直接复用Animal提供的breath()方法来实现Bird的breath()方法。 a.breath(); } public void fly() { System.out.println("我在天空自在的飞翔..."); } } class Wolf { // 将原来的父类组合到原来的子类,作为子类的一个组合成分 private Animal a; public Wolf(Animal a) { this.a = a; } // 重新定义一个自己的breath()方法 public void breath() { // 直接复用Animal提供的breath()方法来实现Wolf的breath()方法。 a.breath(); } public void run() { System.out.println("我在陆地上的快速奔跑..."); } } public class CompositeTest { public static void main(String[] args) { // 此时需要显式创建被组合的对象 Animal a1 = new Animal(); Bird b = new Bird(a1); b.breath(); b.fly(); // 此时需要显式创建被组合的对象 Animal a2 = new Animal(); Wolf w = new Wolf(a2); w.breath(); w.run(); } }
何时使用组合或者继承
组合
是“有 has-a
”关系,继承
是“是 is-a
”关系。
- 比如
Dog和Animal类
应该使用继承
关系,因为用一个动物组合成一个狗毫无意义,狗不是由动物组成的,反而狗是动物(is-a关系)
; - 比如
Person类和Head类
就应该使用组合
关系,因为一个人由头组合(has-a关系)
,而不是头是人。
- 比如