处理概括关系之十一 :Replace Inheritance with Delegation(以委托取代继承)

某个subclass 只使用superclass 接口中的一部分,或是根本不需要继承而来的数据。

在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)。

·编译,测试。

范例:(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();

  }

现在我可以编译并测试。如果我忘记加入某个请托函数,编译器会告诉我。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值