你慎用继承了吗?

作者爱说话

Hello,大家好,我是 行云

这是原创的第 10 篇文章,希望今天这篇文章能带给你一点思考和启发

前阵子听朋友说,什么垃圾垃圾公众号文章,我说咋了,他说微信公众号推的啥,“面试阿里 P7 岗,第六题就被干掉”、“十年码农面试,被微服务坑惨了,真实经历”、“新来的同事把项目性能优化了一遍,看看他是怎么做到了?”

因为我也写微信公众号,我听到这些文章,我就觉得,应该是“恰饭”文章,我不反对“恰饭”文章,因为不管每一篇文章质量如何,只要是原创的文章,后面必定是作者用心的输出,只要是有用心的付出都必定希望得到一些正反馈,无论是粉丝、阅读量、亦或是接一些这种广告,这些都是无可厚非的行为

但是这种带诱惑性质标题的文章会让人感觉不太舒服,就比如你满心期待掀起的头盖里是倾国倾城的美女,结果掀开发现是这(本来想贴贴图片,但是感觉贴网上图片也不太尊重人,哈哈哈,读者自行脑补),多少都会有点失望,然后像我的朋友那样带点被骗的感觉,取消公众号的关注,这对公众号也是得不偿失吧,我觉得每一个公众号的主人写文的初心都不是为了赚钱吧

话又说回来了,如果不带这种带诱惑性质标题的文章,估计阅读量翻车的时候,金主爸爸,马*兵老师要不开心了,至今还在微信公众号圈外的我,无法体会这种纠结的感觉

何为继承?

王经理:今天我来给你们讲一讲使用继承的正确姿势,我们都知道,Java 是一种面向什么编程的语言?

林步动:我知道,我知道,是面向工资编程 😄

王经理:👨 小林,你今年 3.25 没跑了

小美:是面向对象编程

林不动:对象是这样的吗?

王经理白了一眼林步动后:

面向对象的编程语言,具有三大特性,继承、封装、多态

首当其冲的就是继承,以一个类(父类,基类)作为基础,复制它,然后通过添加和修改这个副本(子类)来创建新的类,这就是继承做的事。 继承是面向对象编程中,不可或缺的一部分。它使我们的代码富有层次感,也为多态打下了结实的语法地基

但是可以多继承吗?就是一个类继承多个父类?

林步动:当然不可以,那么多父类,儿子都不认识谁是真正的爸爸了

王经理:对,对于继承可能还会有这样的一个争论,“继承应该只覆盖基类的方法(而并不添加在基类中没有的新方法)” ,但是往往来说,继承是个“is - a”关系,如何衡量你的继承是否是正确的,就是看你的继承是否满足 LSP(里氏替换原则),简单来说,就是任何父类可以出现的地方,子类都能够出现

林步动:太抽象了,我来举个例子给小美听

小美:不用啊,我能听懂

林步动:不,你不懂。

继承是个“is - a”关系“,意思就是,妈妈叫我们去买水果,我们买回来苹果是可以的,买回来香蕉也是可以的,但是我们买回来的是薯片、可乐、汉堡、辣条就不行,会被妈妈打,在实际代码环境中,如果父类引用直接使用子类引用来代替,可以编译正确并执行,输出结果符合子类场景的预期,那么这两个类之间就符合 LSP,就可以完美的使用继承

你乱用继承了吗?

王经理:小林说的还是有点道理的,因为继承使用起来非常的方便快捷,我们在撸代码的时候,突然看到,这个父类有我们想要的东西,第一反应,不用造轮子了,继承它,奥利给。所以继承就像保健品一样,被我们乱吃,乱用 ,但是

所以我们需要对继承有个“敬畏”之心,认清错误使用继承会造成什么样的后果

小美:我知道经理,乱用继承,会造成方法污染,比如鸟会飞,不能因为鸵鸟带个鸟字,就让鸵鸟继承鸟,发现鸵鸟不会飞,只会把头埋进土里

子类一旦要继承父类,就说明子类可以肆无忌惮的调用父类的一切方法,我们不能强迫鸵鸟学会飞翔,所以对是否可以继承得有一个清楚的认知

林步动:我也知道经理,乱用继承,会造成方法爆炸💥,比如一个父类非常受欢迎,它的儿子也非常受欢迎,它的孙子也非常受欢迎,它的曾孙子也非常受欢迎,不断地继承后达到了几百代同堂(具有几百个方法),对于具有选择综合症的人,这个方法可以实现我想要的功能,那个方法也可以实现我想要的功能,不对,另一个方法也可以,造成了使用不便和安全隐患

王经理:对,有些场景下,其实优先采用组合或聚合关系来复用其他类的能力,或许是一个更好的选择,《Effective Java 中文版第2版》书中第16条中也说到:继承是实现代码复用的有力手段,但它并非永远是完成这项工作的的最佳工具。

组合关系

王经理:组成其实是一种 “belong-to” 的关系类型。这意味着其中一个对象是逻辑上较大的结构,其中包含另一个对象。换句话说,它是其他对象的一部分或成员。 或者,我们通常称之为"has-a"关系

林步动:就是聚合是体现的是整体与部分、拥有的关系(这不是哲学),即has-a的关系

看下面一段代码:

public class Package {
    // 钱包里有许多钱
    private List<Money> money; 

    // ...
}

在代码层面,聚合可以看作,一个钱包里可以有许多钱 ,但是钱包里不一定有许多钱,因为可能是个穷光蛋的钱包

has-a 不是 必须 has,钱包是可以整体,钱是个部分,可以分离开,他们都具有他们自己的生命周期

组合关系

王经理:

组合体现的是一种 contains-a 的关系,这种关系比聚合更强,也称为强聚合。

先看一段代码:

public class Nose {
    private Eye eye = new Eye();  //一个人有鼻子有眼睛
    private Nose nose = new Nose();

    // .... 
}

组合同样是整体与部分的联系,但此时整体与部分不可分割,就像中国与台湾一样,如果整体的生命周期结束也就意味着部分的生命周期结束。

就像正常人有鼻子有眼睛,如果人一旦 die 了,鼻子和眼睛的生命周期也会结束,而且,鼻子和眼睛不能脱离人单独存在

继承还是组合?

事物的存在即有它的道理

继承和组合都是实现系统功能重用,代码复用的最常用的有效的设计技巧

很多人都知道面向对象中有一个比较重要的原则『多用组合、少用继承』或者说『组合优于继承』,组合确实比继承更加灵活,也更有助于代码维护,在需求可以实现的相同情况下,优先使用组合而不是继承

因为组合更安全,更简单,更灵活,更高效,让我们不得不爱上它

但是不能片面断定继承就一点用都没有了,前面说的是【在同样可行的情况下】。有些场景还是需要使用继承的,或者是更适合使用继承。

继承要慎用,其使用场合仅限于你确信使用该技术有效的情况。

一个判断方法是,问一问自己是否需要从新类向基类进行向上转型。如果是必须的,则继承是必要的。反之则应该好好考虑是否需要继承。

只有当子类真正是超类的子类型时,才适合用继承。换句话说,对于两个类A和B,只有当两者之间确实存在 is-a 关系的时候,类 B 才应该继承 类A

参考文章:

《Effective Java 中文版第2版》

《码出高效》

重新认识java - Sharember


我是 行云,点个赞再走吧,我们下期再见 👋

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值