重构类关系-Replace Inheritance with Delegation以委托取代继承十一
重构类关系-Replace Inheritance with Delegation以委托取代继承十一
1.以委托取代继承
1.1.使用场景
某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据。
在子类中新建一个字段用以保存超类;调整子类函数,令它改而委托超类;然后去掉两者之间的继承关系。
继承是个好东西,但有时候它并不是你要的。你常常会遇到这样的情况:一开始继承了一个类,随后发现超类中的许多操作并不真正适用于子类。这种情况下,你所拥有的接口并未真正反映出子类的功能。或者,你可能发现你从超类中继承了一大堆子类并不需要的数据,抑或你可能发现超类中的某些protected函数对子类并没有什么意义。
你可以选择容忍,并接受传统说法:子类可以只使用超类功能的一部分。但这样做的结果是:代码传达的信息与你的意图南辕北辙——这是一种混淆,你应该将它去除。
如果以委托取代继承,你可以更清楚地表明:你只需要受托类的一部分功能。接口中的哪一部分应该被使用,哪一部分应该被忽略,完全由你主导控制。这样做的成本则是需要额外写出委托函数,但这些函数都非常简单,极少可能出错。
1.2.如何做
- 在子类中新建一个字段,使其引用超类的一个实例,并将它初始化为this。
- 修改子类内的所有函数,让它们不再使用超类,转而使用上述那个受托字段。
- 每次修改后,编译并测试。
- 你不能这样修改子类中通过super调用超类函数的代码,否则它们会陷入无限递归。这种函数只有在继承关系被打破后才能修改。
- 去除两个类之间的继承关系,新建一个受托类的对象赋给受托字段。
- 针对客户端所用的每一个超类函数,为它添加一个简单的委托函数。
- 编译,测试。
1.3.示例
滥用继承的一个经典范例就是让Stack类继承Vector类──Java 1.1的工具库(java.util)恰好就是这样做的。(这些淘气的孩子啊!)不过,作为范例,我只给出一个比较简单的形式:
class MyStack extends Vector {public void push(Object element) {insertElementAt(element,0);}public Object pop() {Object result = firstElement();removeElementAt(0);return result;}
}
只要看看MyStack的用户,我就会发现,用户只要它做4件事:push()、pop()、size()和isEmpty()。后两个函数是从vector继承来的。
我要把这里的继承关系改为委托关系。首先,我要在MyStack中新建一个字段,用以保存受托的Vector对象。一开始我把这个字段初始化为this,这样在重构进行过程中,我就可以同时使用继承和委托:
private Vector _vector = this;
现在,我开始修改MyStack 的函数,让它们使用委托关系。首先从push() 开始
public void push(Object element) {_vector.insertElementAt(element,0);}
此时我可以编译并测试,一切都将运转如常。现在轮到pop()
public Object pop() {Object result = _vector.firstElement();_vector.removeElementAt(0);return result;}
修改完所有子类函数后,我可以打破与超类之间的联系了:
class MyStack extends Vectorprivate Vector _vector = new Vector();
然后,对于Stack客户端可能用到的每一个Vector函数 ,我都必须在MyStack中添加一个简单的委托函数:
public int size() {return _vector.size();}public boolean isEmpty() {return _vector.isEmpty();}
现在我可以编译并测试。如果我忘记加入某个委托函数,编译器会告诉我。
重构类关系-Replace Inheritance with Delegation以委托取代继承十一相关推荐
- Replace Inheritance with Delegation(以委托取代继承)
某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据 重构:在子类中新建一个字段用来保存超类,调整子类函数,令它改而委托超类,然后去掉两者的继承关系
- 重构之以委托取代继承
参考<重构> (1)原始例子: <?php class Worker {public function inhome(){ echo "inhome!!!".'& ...
- 委托和继承(Delegation and Inheritance)
写在前面 学习面向对象编程语言,不能避免的会需要掌握委托和继承的概念,然而二者对初学者来说很难区分,本文就笔者的理解,谈谈二者的主要区别. 为避免引起混淆,本文使用了"委托类"和& ...
- UML类关系(依赖,关联,聚合,组合,泛化,实现)
转自https://blog.csdn.net/k346k346/article/details/59582926 在学习面向对象设计时,类关系涉及依赖.关联.聚合.组合和泛化这五种关系,耦合度依次递 ...
- RocketMQ类关系图之NameServer
2019独角兽企业重金招聘Python工程师标准>>> 由于博客不能上传文档,只能截图. 在此感谢RocketMQ_calvinzhan同学的分享! 如何获得? 打开"码代 ...
- 学习笔记之-Activiti7工作流引擎,概述,环境搭建,类关系图,使用Activiti BPMN visualizer,流程变量,组任务 网关,Activiti整合Spring SpringBoot
本篇学习笔记是观看黑马程序员Activiti7视频而得 Activiti7 一.工作流介绍 1.1 概念 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是" ...
- 认识 UML 类关系——依赖、关联、聚合、组合、泛化
文章目录 1.依赖(Dependency) 2.关联(Association) 3.聚合(Aggregation) 4.组合(复合,Composition) 5.泛化(Generalization) ...
- django-模型类关系
模型类关系 一对多 多对多 一对一 外键字段的定义 一对一,多对多,外键字段定义在哪张表都可以 一对多,外键字段一定要定义在多的一方
- java实体类实现抽象类_java接口、抽象类、实体类关系介绍
接口:接口是一个引用类型,与类相似,不过在接口中只能包含常量,方法名和嵌套类型.没有构造器,所以不能被实例化只能被类所实现或者被另外的接口所继承.在接口中声明的方法没有方法体. 抽象类:将类层次中共有 ...
最新文章
- Android 抓取app进程 hprof 文件
- fcode-页面九宫格自动锁屏jquery插件
- vue 计算属性和data_vue之watch和计算属性computed
- 计算机科技与技术对应岗位,计算机技术与软件专业技术资格名称及岗位基本任职条件...
- linux指令:时间与日期
- ubuntu安装docker以及dockerfly
- tensorflow之conv2d
- 基于物理的渲染详尽指南 卷1光与介质:基于物理的渲染和着色理论
- 电商项目面试题 及mysql面试题 太难没啥用
- cgroup学习(六)——attach task
- jetbrains goland配置go开发环境
- linux系统 删除文件命令
- 华为freebuds4i降噪方法分享(教程分享)
- 【python做接口测试的学习记录day9——pytest自动化测试框架之yaml数据驱动封装】
- 《中国合伙人》:致我们即将逝去的青春
- [转]JFFS2源代码情景分析Beta2
- ES6,ES7,ES8,ES9,ES10新特性一览
- oracle配DISPLAY,ORACLE安装DISPLAY变量设置
- P528 List接口常用实现类的对比及源码分析
- 设计模式综合-媒体播放器的实现
热门文章
- SQL Sever 2012
- Linux--网络命令大全--使用
- 成电计算机考研专业课,2020成电软件工程考研经验贴
- reverse()函数
- 基于Java实现动态数组
- 一维离散小波变换原理和代码实现
- j3455linux网卡不亮,J3455 ProxmoxVE v6.0-4 直通物理网卡教程
- 机器学习几种距离比较:欧拉距离(Euclidean Distance)、曼哈顿距离(Manhattan Distance)和明可夫斯基距离(Minkowski Distance)
- php统计邮件打开率,监控 Amazon SES 电子邮件的打开率、点击率和退回率
- 固定资产管理系统(论文+PPT+源码)