何时该使用"委托"(Delegation)? (转)

何时该使用"委托"(Delegation)? (转)[@more@]

由于类别继承和物件组合是物件导向软体设计的两个主要方法﹔在不便使用继承的场合里﹐常使用物件组合﹐此时也常用委托观念。XML:NAMESPACE PREFIX = O />

 

 


  物件A 把外界传来的讯息" 转送" 给物件B ﹐由B 处理之﹐我们称物件A 委托物件B 。当一群物件互相沟通分工合作时常用妥托观念。虽然C++ 并未直接支援委托功能﹐但能间接地表达出来。由于类别继承(Class Inheritance) 和物件组合(object Composition)是物件导向软体设计的两个主要方法﹔在不便使用继承的场合里﹐常使用物件组合﹐此时也常用委托观念。例如﹐有个" 长方形" 类别﹕

  ASPectratio="t">windows/TEMP/msoclip1/01/clip_image001.wmz" o:title="">1165977544062.gif

  接着想设计个" 正方形" 类别﹐大多数人会先想到继承功能﹕

  1165977544078.gif

如此就可重复使用(Reuse)这 Area()函数了。

  这个继承结构有些美中不足之处﹐例如Square从Rectangle 继承了SetWidth()及SetHeight() 函数﹐对Square()而言是无用而且有害。万一呼叫到Square的SetWidth()﹐则Square的4 边就不等长了﹗这时﹐可改用物件组合方式来代替继承﹕

 

1165977544078.gif   当Square之物件接到外界传来的Area()讯息时﹐就委托Rectangle 之物件代为处理。以C++ 表达如下﹕

 

Rectangle

class Rectangle {

  double width, height;

  public:

  void SetWidth(double w)

  { width=w; }

   void SetHeight(double h) 

  { height=h; }

  double Area()

  { return width*height; }

  };

class Square {

  Rectangle *rectangle;

  public:

  Square() { rectangle = new Rectangle; }

  void SetLength(double len)

  { rectangle->SetWidth(len);

  rectangle->SetHeight(len);

  }

  double Area()

  { return rectangle->Area(); }

 };

 

  SetWidth()及SetHeight() 不属于Square类别﹐就无上述的副作用了。但也些缺点﹕rectangle 值是在程式执行时才确定的﹐也就是委托关系是在执行时才建立起来。一旦rectangle 值改变了﹐就改变委托的对象。所以委托是很有弹性的,但却常令程式更复杂。反过来,继承关系是在程式编译时就确定了﹐能使程式较清楚﹐但在执行时无法改变继承关系﹐弹性较小。因之﹐继承和委托皆能达到重复使用(Reuse)之目的﹐各有所长各有所短﹐相辅相成才是完美的。简单规则是﹕

 

  「优先考虑使用继承﹐若觉得牵强﹐

  就考虑用委托」

 

请看下述例子﹐有个" 圆形" 类别以及" 正方形" 类别﹐共同衍生出CR类别﹕

 

1165977544078.gif   CR类别的Draw()会先呼叫Square::Draw()绘出正方形﹐再呼叫Circle::Draw()绘出正方形的内接圆。以C++ 表示为﹕

 

Circle

class Circle

 {

  protected:

  int x, y, r;

  public:

  Circle(int a, int b, int)

  :x(a), y(b), z(c) {}

  void Draw()  { .... }

 };

 

Square

class Square

 {

  public:

  virtual int GetX()=0;

  virtual int GetY()=0;

  virtual int GetLength()=0;

  void Draw()

  {  GetX()

  GetY()

  ....

  }

  };

 

class CR

class CR : public Circle,  public Square

 {

  public:

  virtual int GetX()

  { return x; }

  virtual int GetY()

  { return y; }

  virtual int GetLength() 

  { return r*2; }

  void Draw() { ... }

 };

  Square的Draw()函数绘图时﹐会先从CR取得正方形的中心点座标(x,y) 值﹐且取得正方形的边长﹐然后才画出正方形。

  一般而言﹐多重继承(Multiple Inheritance)常有些副作用﹐例如名称的冲突等。为了避免上述双重继承﹐可改用委托方法,如下图。

 

1165977544078.gif 以C++ 表示如下﹕

 

Square

class Square

  {

  Draw(CR *pcr)

  {  pcr->GetX()

  pcr->GetY()

  ....

  }

  };

 

class CR : public Circle

  {

  Square *square;

  public:

  int GetX()  { return x; }

  int GetY()  { return y; }

  int GetLength  { return r*2; }

  void Draw()

  { square->Draw(this); }

  ........

  };

 

 

  继承和委托都是重复使用另一类别或物件中的函数。例如﹐CR继承Square时﹐CR使用Square的Draw()来绘出正方形﹔当继承改为委托时﹐也是一样由Square的Draw()来担任绘正方形的工作。所以﹐若觉得CR继承Square有些麻烦时﹐应可考虑使用委托。虽然委托会令程式复杂些﹐但勉强使用继承﹐后遗症将更大。因为副作用可能会延续到CR的各子孙类别﹗


来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/10790690/viewspace-961292/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/10790690/viewspace-961292/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值