第18 条:复合优先于继承

复合优先于继承

核心:

对于专门为了继承而设计并且具有很好的文档说明的类来说,使用继承是非常安全的。然而,对普通的具体类进行跨越包边界的继承,则是非常危险的。

论证

与方法不同的是,继承打破了封装性
咋的理解了?看如下的例子

public class A {
    //方法功能是说话
    public void say() {
        //一堆说话的实现细节
    }
    //方法功能是唱歌
    public void song() {
        //具体的实现细节
        // 唱歌的前提要先说话,所以调用自身的say()方法
        say();
        //然后一堆唱歌的实现细节
    }
}
public class B extends A{
    @Override
    public void say() {
        //我就想再说话之前先告诉大家一声我要说话了
        System.out.println("我要开始说话了");
        super.say();
    }

    @Override
    public void song() {
        //我就想再唱歌之前先告诉大家一声我要唱歌了
        System.out.println("我要开始唱歌了");
        super.song();
    }

    public static void main(String[] args) {
        B b = new B();
        //现在我要高歌一首
        b.song();
    }
}

结果

我要开始唱歌了
我要开始说话了

这结果怎么是这样子,我明明就是想唱歌呀,为啥又说我开始说话了,
其实是因为类B继承了类A ,在类A中的song实现细节中用了say()方法,导致在类B中先走了song()方法,又走了say()方法,但是对于类B来说我不想知道你走了啥方法,我就是想要的功能而已,唱歌就是唱歌,说话就是说话。当然我们也可以将类A中的song()方法改成不调用say()方法,但是这个不应该和类A的实现细节有关系啊,我只是提供了我的API接口,功能不变的情况下,我的内部实现细节怎么变都应该是没有问题的啊,所以这就是继承暴漏了API的实现细节出现的问题。
而复合就不会有这样的问题了,把类A做为一个私有域放入类B中。再调用类A的song()方法

public class B {
    private A a;

    public B(A a) {
        this.a = a;
    }
    public void say() {
        System.out.println("我要开始说话了");
        a.say();
    }

    public void song() {
        System.out.println("我要开始唱歌了");
        a.song();
    }
    
    public static void main(String[] args) {
        B b = new B(new A());
        //现在我要高歌一首
        b.song();
    }
}

结果

我要开始唱歌了

可以看出复合屏蔽了类的实现细节,专注于功能而不关注细节

所以继承要严格的遵循is-a的关系,否则不能瞎用继承,在用继承的时候想好继承是不是只是为了扩展功能。否则就不得不用复合来代替继承了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值