基于第三方软件开发的策略探讨(2)

 

Solution 3: 应用 decorator design pattern

 

Decorator pattern采用对象组合的方式为对象增加新特性。

 

关于 Decorator, GOF 书中给出了以下使用情况:

1)         在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

2)         处理那些可以撤消的职责。

      3)         当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

我们在这里遇到的其实就是第 1类问题。当第三方软件提供的特性不满足客户的要求的时候,我们就需要自己添加这些特性, Decorator就提供了一种在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责 的方法。所以可以使用这种模式。

 

结构:

<!-- /* Font Definitions */ @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 680460288 22 0 262145 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 680460288 22 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0in; margin-bottom:.0001pt; mso-pagination:widow-orphan; font-size:11.0pt; font-family:Arial; mso-fareast-font-family:宋体; mso-bidi-font-family:"Times New Roman";} @page Section1 {size:8.5in 11.0in; margin:1.0in 1.25in 1.0in 1.25in; mso-header-margin:.5in; mso-footer-margin:.5in; mso-paper-source:0;} div.Section1 {page:Section1;} -->

 

 

结构说明:

1)        抽象构件角色( Component):定义一个抽象接口,以规范准备接收附加责任的对象。

2)        具体构件角色 (Concrete Component):这是被装饰者,定义一个将要被装饰增加功能的类。

3)        装饰角色 (Decorator):维护一个 Component对象的实例,并定义了和 Component一致的接口。

4)        具体装饰角色 (Concrete Decorator):负责给构件添加增加的功能。

 

协作说明

Decorator将请求转发给它的 component对象,并且有可能在转发请求前后执行一些附加的动作。

 

实现要点:

  • Decorator component的接口必须是一致的。因此所有的 concreteDecorator必须有一个公共父类。
  • 保持 Component的简单性。为了保持接口的一致性, ConcreteComponent Decorator必须有一个公共父类 Component。因此保持 component的简单性非常重要。它应集中与定义接口而不是数据。否则因为 component过于复杂和庞大,导致在实际中可能难以使用。
  • decorator模式使用时有一个重要限制。如果我们从抽象基类派生,我们必须实现抽象基类的每一个虚方法(或者,对于非虚基类,要么重载基类的方法,要么使用基类的实现,但这就丢失了 ConcreteComponent子类中重载的实现,即失去( -)了特性,这与 Decorator模式进行修饰,即加( +)特性的实质有悖),而当虚方法的数目众多时,这将成为一种负担。逐一实现它们是一件很繁琐的事情,而且并不提供新的功能。

 

代码示例

 

首先创建一个 TextView 对象。参看前面的代码。

 

然后创建一个 Component,component 拥有新增特性所需要的接口, Textview FancyBorder 都从 Component 继承而来。

 

然后在创建一个 FancyBorder, 它包含一个指向 Component 的指针,重新定义 Draw 接口,除了继承 component Draw 方法之外,增加了绘制边框的动作。

 

public class FancyBorder {

   private Component component;

   public FancyBorder(Component component) {

      this.component = component;

   }

   Private void DrawBorder(){

        //code to draw the FancyBorder object itself.

   }

 

   public void draw() {

      component.draw;

      DrawBorder;

   }

}

 

public class Client {

   public static void main(String[] args) {

      TextView data = new TextView();

      Component borderData = new FancyBorder(data);

      Component scrolledData = new VertScrollbar(data);

      Component borderAndScrolledData = new HorzScrollbar(borderData);

      borderAndScrolledData.draw;

   }

}

 

效果

Decorator模式有两个优点和缺点。这里做一个简单阐述。

1, 比静态继承要灵活。一般的继承和 decorator都可以扩展对象的功能, decorator提供了更加灵活的向对象添加职责的方式。这就是“优先使用对象组合”原则的体现。

2, 通过使用不同的对象组合方式,可以设计出很多不同行为的组合,同时避免了“类爆炸”的出现。

使用 decorator也有以下的缺点:

1, 由于对象组合方式产生了更多的看上去类似的小对象,导致很难学习这个系统,而且排错也更困难一点。

 

 

Solution4 Decorator  design pattern C 语言简化版变形。使用分离的应用程序对象增加新特性。

 

如果使用面向对象语言 C++或者 java的话,直接应用 decorator是一个完美的方案。 Decorator对于上层应用程序是透明的。上层应用程序不需要做任何改动就可以增加新特性。但是如果使用非面向对象语言比如 C语言,情况就不一样了。虽然从理论上讲非面向对象语言可以实现类的继承等特性,但是非常困难;而且需要重新全部设计接口函数,比较麻烦。在通信系统软件,实时系统软件中 C语言的应用还是很广泛的,如何在 C语言环境下应用设计模式的思想进行设计也是一个很有意思的话题,这里我采用一种比较变通的做法,借鉴 Decorator的思想,采用一种适合 C语言的的实现方式。这就是 solution4。和 Solution3不同的是,它保留了对象组合、分离设计的思想,舍弃了一些继承的层次,因此结构更加简单 ,比较适合 C语言环境使用。

 

实现要点:

为每一个需要增加新特性的对象 ConcreateComponent创建独立的应用程序维护的对象 ConcreateDecorator(Decorator),根据特性的特点,可以增加一个或者多个,用于保存用户增加的特性和方法。 ConcreteDecorator对象包含对原有对象 ConcreteComponent的引用指针,然后在需要使用新特性的时候使用 ConcreteDecorator及其 API,如果需要使用老特性,不是采用 solution3继承的方法,而是依然使用原来的对象 ConcreteComponent及其 API

 

代码示例:

 

这次的代码使用 C语言。

 

首先创建 TextView

 

typedef struct TextView TextView;

typedef void (*tvDrawFunc)(TextView* tv);

 

typedef struct TextView {

      tvDrawFunc draw;

}TextView;

 

Void tvInit(TextView* tv){

      tv->draw = tvDraw;

      //code to init the TextView structure itself;

}

 

Void tvDraw(TextView* tv){

      //code to draw the TextView object itself;

}

 

typedef struct FancyBorder FancyBorder;

typedef void (*fbDrawFunc)(FancyBorder* fb);

 

typedef struct FancyBorder {

      TextView   *tv; //reference to TextView obj;

 

      fbDrawFunc preDraw;     // optional. the action before draw;

 

      fbDrawFunc DrawEx;     // optional. modified draw action;

     

      fbDrawFunc postDraw;    // optional. the action after draw;

       

}FancyBorder;

 

void fbInit(FancyBorder* fb, TextView *tv){

      fb->tv = tv;

      fb->DrawEx = fbDraw;

      fb->preDraw = fbPreDraw;

      fb->postDraw = fbPostDraw;

      //code to init the FancyBorder structure itself;

}

 

void fbDraw(FancyBorder* fb){

      assert(NULL != tv);

      (*fb->tv->draw)();

      //code to draw the FancyBorder object itself;

}

void fbPreDraw(FancyBorder* fb){

 

      //code to draw the FancyBorder object itself;

}

void fbPostDraw(FancyBorder* fb){

 

      //code to draw the FancyBorder object itself;

}

 

 

void main(int argc, char[] argv) {

      TextView data;

      FancyBorder fb;

     

      tvInit(&data);

      fbInitFunc(&fb,&data);

 

      fb.preDraw(&fb);        // add pre-action here

 

      fb.tv->draw(&data);     // use the original draw action.

 

Fb.DrawEx(&fb);         //use fb.DrawEx(&fb) instead if you want to change the original feature.

 

      fb.postDraw(&fb);       //add post-action here.      

   }

 

 

solution3中, Decorator使用 Decorator对象代替原来的 component对象(本质也是一种组合方式)。而 solution4采用 ConcreteComponentj+ ConcreteDecorator的组合方式 这样 ConcreteDecorator只增加新的特性就行了 需要用到原有特性的地方 可以调用 ConcreteComponent的特性。

 

效果:

 

采用这样的方法,当第三方软件升级的时候,由于原有的对象 ConcreteComponent 不知道 ConcreteDecorator 的存在, ConcreteDecorator 仅从外部改变并增加了新特性,这样,就可以方便地升级第三方软件,还可以把自己实现的新特性方便地移植到新的软件版本中去,达到重用的目的。

这种方法对于 C 语言环境的编程者是比较适用的。既保留了设计模式的灵活性,又简化了实现。

 

总结

在基于第三方代码开发的过程中,考虑到第三方代码的完整性和未来可能的升级改动,保持其代码的独立性是非常重要的,因此应用程序在增加新特性的时候就必须采用特别的策略。应用 Decorator模式思想进行设计,封装自己的新增特性,可以在未来方便地支持第三方软件的升级和自己开发的新特性的重用。

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值