多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
### Replace Delegation with Inheritance(以继承取代委托) 你在两个classes 之间使用委托关系(delegation),并经常为整个接口编写许多极简单的请托函数(delegating methods)。 让「请托(delegating)class」继承「受托 class (delegate)」。 ![](https://box.kancloud.cn/2016-08-15_57b1b5e7d248f.gif) **动机(Motivation)** 本重构与 Replace Delegation with Inheritance 恰恰相反。如果你发现自己需要使用「受托 class」中的所有函数,并且费了很大力气编写所有极简的请托函数(delegating methods),本重构可以帮助你轻松回头使用「继承」。 两条告诫需牢记于心。首先,如果你并没有使用「受托class 」的所有函数(而非只是部分函数),那么就不应该使用Replace Delegation with Inheritance,因为subclass 应该总是遵循(奉行)superclass 的接口。如果过多的请托函数让你烦心,你有别的选择:你可以通过 Remove Middle Man 让客户端自己调用受托函数,也可以使用Extract Superclass 将两个classes 接口相同的部分提炼到superclass 中, 然后让两个classes 都继承这个新的superclass ;你还可以以类似手法使用Extract Interface。 另一种需要当心的情况是:受托对象被不止一个其他对象共享,而且受托对象是可变的(mutable)。在这种情况下,你就不能将「委托关系」替换为「继承关系」,因为这样就无法再共享数据了。数据共享是必须由「委托关系」承担的一种责任,你无法把它转给「继承关系」。如果受托对象是不可变的(immutable),数据共享就不 成问题,因为你大可放心地拷贝对象,谁都不会知道。 **作法(Mechanics)** - 让「请托端」成为「受托端」的一个subclass 。 - 编译。 - 此时,某些函数可能会发生冲突:它们可能有相同的名称,但在返回型别(return type)、异常指定(exceptions)或可视性(visibility)方面有所差异。你可以使用Rename Method 解决此类问题。 - 将「受托值域」(delegated field)设为「该值域所处之对象自身」。 - 去掉简单的请托函数(delegating methods)。 - 编译并测试。 - 将所有其他「涉及委托关系」的动作,改为「调用对象自身(继承而来的函 数)」。 - 移除「受托值域」(delegated field)。 **范例:(Example)** 下面是一个简单的Employee,将一些函数委托给另一个同样简单的Person : ~~~ class Employee { Person _person = new Person(); public String getName() { return _person.getName(); } public void setName(String arg) { _person.setName(arg); } public String toString () { return "Emp: " + _person.getLastName(); } } class Person { String _name; public String getName() { return _name; } public void setName(String arg) { _name = arg; } public String getLastName() { return _name.substring(_name.lastIndexOf(' ')+1); } } ~~~ 第一步,只需声明两者之间的继承关系: ~~~ class Employee extends Person ~~~ 此时,如果有任何函数发生冲突,编译器会提醒我。如果某几个函数的名称相同、但返回型别不同,或抛出不同的异常,它们之间就会出现冲突。所有此类问题都可以通过Rename Method 加以解决。为求简化,我没有在范例中列出这些麻烦情况。 下一步要将「受托值域」(delegated field)设值为「该值域所处之对象自身」。同时,我必须先删掉所有简单的请托函数(例如getName() 和setName())。如果留下这种函数,就会因为无限递归而引起系统的call stack 满溢(overflow)。在此范例中,我应该把Employee 的getName() 和setName() 拿掉。 一旦Employee 可以正常工作了,我就修改其中「使用了请托函数(译注:或受托值域)」的函数,让它们直接调用「从superclass 继承而来的函数」: ~~~ public String toString () { return "Emp: " + getLastName(); } ~~~ 摆脱所有涉及委托关系的函数后,我也就可以摆脱_person 这个(受托)值域了。