重构类关系-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以委托取代继承十一相关推荐

  1. Replace Inheritance with Delegation(以委托取代继承)

    某个子类只使用超类接口中的一部分,或是根本不需要继承而来的数据 重构:在子类中新建一个字段用来保存超类,调整子类函数,令它改而委托超类,然后去掉两者的继承关系

  2. 重构之以委托取代继承

    参考<重构> (1)原始例子: <?php class Worker {public function inhome(){ echo "inhome!!!".'& ...

  3. 委托和继承(Delegation and Inheritance)

    写在前面 学习面向对象编程语言,不能避免的会需要掌握委托和继承的概念,然而二者对初学者来说很难区分,本文就笔者的理解,谈谈二者的主要区别. 为避免引起混淆,本文使用了"委托类"和& ...

  4. UML类关系(依赖,关联,聚合,组合,泛化,实现)

    转自https://blog.csdn.net/k346k346/article/details/59582926 在学习面向对象设计时,类关系涉及依赖.关联.聚合.组合和泛化这五种关系,耦合度依次递 ...

  5. RocketMQ类关系图之NameServer

    2019独角兽企业重金招聘Python工程师标准>>> 由于博客不能上传文档,只能截图. 在此感谢RocketMQ_calvinzhan同学的分享! 如何获得? 打开"码代 ...

  6. 学习笔记之-Activiti7工作流引擎,概述,环境搭建,类关系图,使用Activiti BPMN visualizer,流程变量,组任务 网关,Activiti整合Spring SpringBoot

    本篇学习笔记是观看黑马程序员Activiti7视频而得 Activiti7 一.工作流介绍 1.1 概念 工作流(Workflow),就是通过计算机对业务流程自动化执行管理.它主要解决的是" ...

  7. 认识 UML 类关系——依赖、关联、聚合、组合、泛化

    文章目录 1.依赖(Dependency) 2.关联(Association) 3.聚合(Aggregation) 4.组合(复合,Composition) 5.泛化(Generalization) ...

  8. django-模型类关系

    模型类关系 一对多 多对多 一对一 外键字段的定义 一对一,多对多,外键字段定义在哪张表都可以 一对多,外键字段一定要定义在多的一方

  9. java实体类实现抽象类_java接口、抽象类、实体类关系介绍

    接口:接口是一个引用类型,与类相似,不过在接口中只能包含常量,方法名和嵌套类型.没有构造器,所以不能被实例化只能被类所实现或者被另外的接口所继承.在接口中声明的方法没有方法体. 抽象类:将类层次中共有 ...

最新文章

  1. Android 抓取app进程 hprof 文件
  2. fcode-页面九宫格自动锁屏jquery插件
  3. vue 计算属性和data_vue之watch和计算属性computed
  4. 计算机科技与技术对应岗位,计算机技术与软件专业技术资格名称及岗位基本任职条件...
  5. linux指令:时间与日期
  6. ubuntu安装docker以及dockerfly
  7. tensorflow之conv2d
  8. 基于物理的渲染详尽指南 卷1光与介质:基于物理的渲染和着色理论
  9. 电商项目面试题 及mysql面试题 太难没啥用
  10. cgroup学习(六)——attach task
  11. jetbrains goland配置go开发环境
  12. linux系统 删除文件命令
  13. 华为freebuds4i降噪方法分享(教程分享)
  14. 【python做接口测试的学习记录day9——pytest自动化测试框架之yaml数据驱动封装】
  15. 《中国合伙人》:致我们即将逝去的青春
  16. [转]JFFS2源代码情景分析Beta2
  17. ES6,ES7,ES8,ES9,ES10新特性一览
  18. oracle配DISPLAY,ORACLE安装DISPLAY变量设置
  19. P528 List接口常用实现类的对比及源码分析
  20. 设计模式综合-媒体播放器的实现

热门文章

  1. SQL Sever 2012
  2. Linux--网络命令大全--使用
  3. 成电计算机考研专业课,2020成电软件工程考研经验贴
  4. reverse()函数
  5. 基于Java实现动态数组
  6. 一维离散小波变换原理和代码实现
  7. j3455linux网卡不亮,J3455 ProxmoxVE v6.0-4 直通物理网卡教程
  8. 机器学习几种距离比较:欧拉距离(Euclidean Distance)、曼哈顿距离(Manhattan Distance)和明可夫斯基距离(Minkowski Distance)
  9. php统计邮件打开率,监控 Amazon SES 电子邮件的打开率、点击率和退回率
  10. 固定资产管理系统(论文+PPT+源码)