Java 中的组合与继承

学习 JVM 的时候遇到了组合的概念,回想了下这是面向对象的知识,有点遗忘,所以写下这篇文章加深记忆。
首先,继承和组合都是实现类复用的重要手段,但继承的坏处是会破坏封装性,而采用组合的方式能提供更好的封装性。

继承(is-a) VS 组合(has-a)

下面以组合和继承的综合例子来介绍它们的区别:

要实现的目标:鸟(Bird)和狼(Wolf)都是动物(Animal),动物都有心跳(beat()),会呼吸(beat()),但是鸟会fly(fly()),狼会奔跑(run()),用java程序实现以上描述。


class Animal {
    private void beat() {
        System.out.println("心脏跳动...");
    }

    public void breath() {
        beat();
        System.out.println("吸一口气,呼一口气,呼吸中...");
    }
}

// 继承Animal,直接复用父类的 breath() 方法
class Bird extends Animal {
    // 创建子类独有的方法fly()
    public void fly() {
        System.out.println("我是鸟,我在天空中自由的飞翔...");
    }
}

// 继承Animal,直接复用父类的 breath() 方法
class Wolf extends Animal {
    // 创建子类独有的方法 run()
    public void run() {
        System.out.println("我是狼,我在草原上快速奔跑...");
    }
}

public class InheritTest {
    public static void main(String[] args) {
        // 创建继承自 Animal 的 Bird 对象新实例 b
        Bird b = new Bird();
        // 新对象实例b可以breath()
        b.breath();
        // 新对象实例b可以fly()
        b.fly();
        Wolf w = new Wolf();
        w.breath();
        w.run();
        /*
         * ---------- 运行 Java 程序 ---------- 
         * 心脏跳动... 吸一口气,呼一口气,呼吸中... 
         * 我是鸟,我在天空中自由的飞翔...
         * 心脏跳动... 吸一口气,呼一口气,呼吸中... 
         * 我是狼,我在草原上快速奔跑...
         * 
         * 输出完毕 (耗时 0 秒) - 正常终止
         */
    }
}

// 使用组合方式实现目标
class Animal {
    private void beat() {
        System.out.println("心脏跳动...");
    }

    public void breath() {
        beat();
        System.out.println("吸一口气,呼一口气,呼吸中...");
    }
}

class Bird {
    // 定义一个 Animal 成员变量,以供组合之用
    private Animal a;

    // 使用构造函数初始化成员变量
    public Bird(Animal a) {
        this.a = a;
    }

    // 通过调用成员变量的固有方法(a.breath())使新类具有相同的功能(breath())
    public void breath() {
        a.breath();
    }

    // 为新类增加新的方法
    public void fly() {
        System.out.println("我是鸟,我在天空中自由的飞翔...");
    }
}

class Wolf {
    private Animal a;

    public Wolf(Animal a) {
        this.a = a;
    }

    public void breath() {
        a.breath();
    }

    public void run() {
        System.out.println("我是狼,我在草原上快速奔跑...");
    }
}

public class CompositeTest {
    public static void main(String[] args) {
        // 显式创建被组合的对象实例 a1
        Animal a1 = new Animal();
        // 以 a1 为基础组合出新对象实例 b
        Bird b = new Bird(a1);
        // 新对象实例b可以 breath()
        b.breath();
        // 新对象实例b可以 fly()
        b.fly();
        Animal a2 = new Animal();
        Wolf w = new Wolf(a2);
        w.breath();
        w.run();
        /*
         * ---------- 运行Java程序 ---------- 
         * 心脏跳动... 吸一口气,呼一口气,呼吸中... 
         * 我是鸟,我在天空中自由的飞翔...
         * 心脏跳动... 吸一口气,呼一口气,呼吸中... 
         * 我是狼,我在草原上快速奔跑...
         * 
         * 输出完毕 (耗时 0 秒) - 正常终止
         */
    }
}

总结:

继承和组合都可以实现代码的复用。

  • 如果是 is-a 关系,一个类想要对另外一个类暴露所有接口,继承看起来是更好的选择。
  • .如果是 has-a 关系,组合是更好的选择。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值