处理概括关系之十一 :Replace Inheritance with Delegation(以委托取代继承)
2013-05-16 09:26
501 查看
某个subclass 只使用superclass 接口中的一部分,或是根本不需要继承而来的数据。
在subclass 中新建一个值域用以保存superclass ;调整subclass 函数,令它改而委托superclass ;然后去掉两者之间的继承关系。
![](https://oscdn.geek-share.com/Uploads/Images/Content/201305/e7af03d0ddcd15c94cadb1357005cea8)
动机(Motivation)
继承(Inheritance )是一件很棒的事,但有时候它并不是你要的。常常你会遇到这样的情况:一开始你继承了一个class ,随后发现superclass 的许多操作并不真正 适用于subclass 。这种情况下你所拥有的接口并未真正反映出class 的功能。或者,你可能发现你从superclass 中继承了 一大堆subclass 并不需要的数据,抑或者你可能发现superclass 中的某些protected 函数对subclass 并没有什么意义。
你可以选择容忍,并接受传统说法:subclass 可以只使用superclass 功能的一部分。但这样做的结果是:代码传达的信息与你的意图南辑北辙——这是一种裩淆,你应该将它去除。
如果以委托(delegation)取代继承(Inheritance ),你可以更清楚地表明:你只需要受托类(delegated class)的一部分功能。接口中的哪一部分应该被使用,哪一部分应该被忽略,完全由你主导控制。这样做的成本则是需要额外写出请托函数(delegating methods),但这些函数都非常简单,极少可能出错。
作法(Mechanics)
范例:(Example)
「滥用继承」的一个经典范例就是让Stack class 继承Vector class 。Java 1.1的utility library(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 用户,我就会发现,用户只要它做四件事:push()、pop()、size() 和 isEmpty() 。后两个函数是从Vector 继承来的。
我要把这里的继承关系改为委托关系。首先,我要在中新建一个值域,用以保存「受托之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;
}
修改完所有subclass 函数后,我可以打破与superclass 之间的联系了 :
class MyStack extends Vector
private Vector _vector = new Vector();
然后,对于Stack 客户端可能用到的每一个Vector 函数(译注:这些函数原本是 继承而来的),我都必须在中添加一个简单的请托函数(delegating method):
public int size() {
return _vector.size();
}
public boolean isEmpty() {
return _vector.isEmpty();
}
现在我可以编译并测试。如果我忘记加入某个请托函数,编译器会告诉我。
在subclass 中新建一个值域用以保存superclass ;调整subclass 函数,令它改而委托superclass ;然后去掉两者之间的继承关系。
动机(Motivation)
继承(Inheritance )是一件很棒的事,但有时候它并不是你要的。常常你会遇到这样的情况:一开始你继承了一个class ,随后发现superclass 的许多操作并不真正 适用于subclass 。这种情况下你所拥有的接口并未真正反映出class 的功能。或者,你可能发现你从superclass 中继承了 一大堆subclass 并不需要的数据,抑或者你可能发现superclass 中的某些protected 函数对subclass 并没有什么意义。
你可以选择容忍,并接受传统说法:subclass 可以只使用superclass 功能的一部分。但这样做的结果是:代码传达的信息与你的意图南辑北辙——这是一种裩淆,你应该将它去除。
如果以委托(delegation)取代继承(Inheritance ),你可以更清楚地表明:你只需要受托类(delegated class)的一部分功能。接口中的哪一部分应该被使用,哪一部分应该被忽略,完全由你主导控制。这样做的成本则是需要额外写出请托函数(delegating methods),但这些函数都非常简单,极少可能出错。
作法(Mechanics)
· | 在subclass 中新建一个值域,使其引用(指向、指涉、refers)superclass 的一个实体,并将它初始化为this。 |
· | 修改subclass 内的每一个(可能)函数,让它们不再使用superclass ,转而使 用上述那个「受托值域」(delegated field)。每次修改后,编译并测试。 |
Ø | 你不能如此这般地修改subclass 中「通过super 调用superclass 函数」的函数,否则它们会陷入无限递归(infinite recurse)。这一类函数只有在继承关系被打破后才能修改。 |
· | 去除两个classes 之间的继承关系,将上述「受托值域」(delegated field)的赋值动作修改为「赋予一个新对象」。 |
· | 针对客户端所用的每一个superclass 函数,为它添加一个简单的请托函数(delegating method)。 |
· | 编译,测试。 |
「滥用继承」的一个经典范例就是让Stack class 继承Vector class 。Java 1.1的utility library(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 用户,我就会发现,用户只要它做四件事:push()、pop()、size() 和 isEmpty() 。后两个函数是从Vector 继承来的。
我要把这里的继承关系改为委托关系。首先,我要在中新建一个值域,用以保存「受托之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;
}
修改完所有subclass 函数后,我可以打破与superclass 之间的联系了 :
class MyStack extends Vector
private Vector _vector = new Vector();
然后,对于Stack 客户端可能用到的每一个Vector 函数(译注:这些函数原本是 继承而来的),我都必须在中添加一个简单的请托函数(delegating method):
public int size() {
return _vector.size();
}
public boolean isEmpty() {
return _vector.isEmpty();
}
现在我可以编译并测试。如果我忘记加入某个请托函数,编译器会告诉我。
相关文章推荐
- 处理概括关系之十二 :Replace Delegation with Inheritance(以继承取代委托)
- 11.11 replace inheritance with delegation(以委托取代继承)
- Replace Delegation with Inheritance(以委托取代继承)
- Replace Delegation with Inheritance (以继承取代委托)
- Replace Inheritance with Delegation(以继承取代委托)
- Replace Inheritance with Delegation (以委托取代继承)
- 重构手法67:Replace Inheritance with Delegation (以委托取代继承)
- 重构手法68:Replace Delegation with Inheritance (以继承取代委托)
- 重构第8天:使用委托代替继承(Replace Inheritance with Delegation)
- 《重构》读书笔记(十一)——第十一章 处理概括关系
- c++面向对象之复合(composition)、委托(delegation)、继承(inheritance)--(boolan)
- 设计模式:Inheritance(继承) 和 Delegation(委托)
- 重构方法之处理概括关系(继承关系)
- 处理概括关系之九 :Collapse Hierarchy(折叠继承关系)
- 重构手法19:Replace Data Value with Object (以对象取代数据值)
- 重构手法29:Replace Record with Data Class (以数据类取代记录)
- 重构手法39:Replace Conditional with Polymorphism (以多态取代条件表达式)
- 改善代码设计 —— 处理概括关系(Dealing with Generalization)
- Replace Array with Object(以对象取代数组)
- Spring MVC中带有继承关系或者含有对象的参数请求处理方式