代码重构:被拒绝的遗赠(Refused Bequest)

网友投稿 896 2022-05-30

什么是被拒绝的遗赠(Refused Bequest)

定义: 被拒绝的遗赠是指:对于某个子类,它只想继承基类的部分函数和数据,不需要基类提供的全部内容,这些不需要的内容就成为了子类的负担

影响: 这种坏味道通常影响并不大,但如果子类拒绝实现部分接口或者基类的方法只适用于某个子类特定的方法,就会对可维护、可扩展性等造成较大影响。

改进目标: 改进不合理的继承体系,使代码结构清晰、可控。

代码重构:被拒绝的遗赠(Refused Bequest)

方法:

•函数/字段下移,让超类只持有子类共享的东西[1]

•以委托取代超类/子类

注[1]:并不建议对所有存在“被拒绝的遗赠”的代码都进行修改,我们经常使用继承复用一些行为,可以很好的应对日常工作,所以修改的成本和收益还是需要开发者自己权衡。但是当“被拒绝的遗赠”使开发人员困惑时,就建议及时处理掉。

案例1

代码背景

描述了个人信息的数据模型;

包含人员信息基类,以及老人、成人、孩子三个子类。老人、成人、孩子类通过继承人员信息类获取相关信息,并实现、重写、调用对应接口、方法等。

人员相关信息,包括年龄、性别、身高、体重、基础退休工资、退休了多少年、上班通勤时间等

计算每个月的养老金、以及是否达到上学年龄的接口

分别获取儿童、成年人、老年人相关个人信息的方法

儿童、成年和老年人子类,都实现了养老金计算、是否达到入学年龄判断接口

症状/问题

子类通过继承父类,了解了过多超出自身需要的方法,也被迫实现了对自己无用的接口,后续其他子类的扩展也都需要了解这些多余信息,严重影响了可扩展、可维护性

父类中提供了isObese实现,但子类中都进行了重写,同时子类通过super,在父类方法中进行调用,导致调用关系复杂,理解难度较大,可读性较差

Old类不需要PersonInfo中孩子和成年人信息,也不该实现isReachSchoolAge接口。

Children不需要PersonInfo中成年人和老年人的信息,也不应该实现calculateMonthlyPensionWage接口

重构目标

将每个子类特有的方法移到相应子类中(比如getChildInfo方法应该移到child中)

公共的行为统一抽取到父类中

重构手法

函数/字段下移

案例2

代码背景

案例包含个人信息和平台账户信息两个类,用于对外提供账户相关信息

案例中平台账户信息类和个人信息类是继承关系。且分别提供了平台账户类作为子类和超类的两种情况。

症状/问题

Person和Platform应当属于两个体系,之间不应该通过继承来进行信息的访问和交换

重构目标

以委托取代子类或超类,消除被拒绝的遗赠

重构对比(案例1)

重构前

父类PersonInfo中包含了getChildren、getAdultInfo、getOldInfo等方法,并不是所有子类都需要的。

重构后

使用函数下移后,父类只有子类公共所需的方法及属性,子类不会获取及实现不需要的功能。

重构对比(案例2)

重构前

PlatAccountInformation和PersonalInformation继承关系,结构设计不合理

重构后

PersonalInformation和PlatAccountInformation为委托关系,可控制传出的属性信息

总结

注[1]:并不建议对所有存在“被拒绝的遗赠”的代码都进行修改,我们经常使用继承复用一些行为,可以很好的应对日常工作,所以修改的成本和收益还是需要开发者自己权衡。但是当“被拒绝的遗赠”使开发人员困惑时,就建议及时处理掉。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:explicit关键字&&static成员
下一篇:Wireshark入门难?您的老朋友告诉你要怎么做!
相关文章