结构模式之Decorator——装饰模式

1、简介
    装饰模式(Decorator)也叫包装器模式(Wrapper)。GOF在《设计模式》一书中给出的定义为:动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。请关注两个重点:
    动态:也就是说无法预先在编译阶段就知道职责的具体内容和添加时机,什么时候添加什么功能完全由客户在运行时刻规定。
    增加:“Decorator模式”往往用于在现有功能的基础上针对不同的对象,添加一些不同的功能,实际上我们还可以改变行为的流程。
2、使用场景及能解决的问题
   
有时候在同一个运行环境下,由于不同对象具有不同的特性导致了它们在执行同一种类型操作时,可能存在一些细小的差别,比如:参数不同、过程不同、方式不同等。
    那么针对这三种情况我们可以采取的解决方法有两种:
    采用继承的方式:定义一个父类的抽象方法,由不同的子类各自实现不同的操作,但一旦子类一多势必带来类的数量膨胀的问题,难以管理;其次如果只是一些局部的细微差别而导致了必须重写整个过程或方法,那么必将导致出现大量的重复代码(即功能相同部分的代码)。有些项目,里面存在了大量的重复代码,到处都是“Copy-Paste”,只是修改了某处的关键参数而已。
    而“Duplicate code”正是《重构-改善既有代码的设计》一书中提到的首要“异味”,这意味着一旦公共部分的功能改变了,那么你有可能需要重新编译几个甚至十几个子类。
    采用“Decorator模式”:首先将功能分解,分成若干个小块,这是为了后面我们可以动态地重组。其次将功能部分抽取出来成为一个接口,通过一个实现了接口的基类完成基本的共有功能。一旦我们需要在基类的功能基础上添加或改变流程,我们就可以通过“Decorator类”实现接口,在接口的实现方法中增加、改变方法的功能或流程。
    比较上面这两种做法,我们可以看到使用了“Decorator模式”后,代码更加简洁了,可重用性和可扩展性更高了。其次由于可以在构造 “Decorator类”的过程中传递参数,我们可以动态的增加、改变原有的功能、流程,而相同部分的功能则委托给基类去完成。
    所以装饰模式适用的场景包括:
     需要扩展一个类的功能,或给一个类增加附加责任。
    需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
    需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变得不现实

3、类图

4、实例
   
装饰模式涉及到一下几个角色:
    * 抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
    * 具体构件(Concrete Component)角色:定义一个将要接收附加责任的类。
    * 装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。
    * 具体装饰(Concrete Decorator)角色:负责给构件对象"贴上"附加的责任。
    下面分别看一下这几个角色的实现:
    Component:
package decorator;
public interface Mobile {
    
void call();
    
void sendMessage();
}
    Concrete Component:
package decorator;
public class MotoMobile implements Mobile {
    
public void call(){
        System.out.print(
"call somebody with Moto");
    }
    
public void sendMessage(){
        System.out.print(
"send message to somebody with Moto");
    }
}
package decorator;

public class NokiaMobile implements Mobile {
    
public void call(){
         System.out.print(
"call somebody with Nokia");
    }
    
public void sendMessage(){
         System.out.print(
"send message to somebody with Nokia");
    }
}


    Decorator:
package decorator;

public class DecoratorMobile implements Mobile {    
    
private Mobile mobile;
    
public DecoratorMobile(Mobile mobile){
        
this.mobile=mobile;
    }
    
public void call(){
        
this.mobile.call();
    }
    
public void sendMessage(){
        
this.mobile.sendMessage();
    }
}

    Concrete Decorator:
package decorator;

public class MobileGPS extends DecoratorMobile {
    
public MobileGPS(Mobile mobile){
        
super(mobile);
    }
    
public void call(){
        
super.call();
        System.out.println(
":use GPS");
    }
    
public void sendMessage(){
        
super.sendMessage();
        System.out.println(
":use GPS");
    }
}
package decorator;

public class MobileBlueTooth extends DecoratorMobile {
    
public MobileBlueTooth(Mobile mobile){
        
super(mobile);
    }
    
public void call(){
        
super.call();
        System.out.println(
":use BlueTooth");
    }
    
public void sendMessage(){
        
super.sendMessage();
        System.out.println(
":use BlueTooth");
    }
}
    最后看看调用的客户端:
package decorator;

public class Client {
    
private static Mobile mobile=new MotoMobile();
    
private static MobileGPS mobileGPS=new MobileGPS(mobile);
    
private static MobileBlueTooth mobileBlueTooth=new MobileBlueTooth(mobile);
    
public static void main(String args[]){
        mobileGPS.call();
        mobileGPS.sendMessage();
        mobileBlueTooth.call();
        mobileBlueTooth.sendMessage();
    }
}

5、优缺点
    比静态继承更灵活:与对象的静态继承相比,Decorator模式提供了更加灵活的向对象添加职责的方式,可以使用添加和分离的方法,用装饰在运行时刻增加和删除职责。
    避免在层次结构高层的类有太多的特征:Decorator模式提供了一种“即插即用”的方法来添加职责,他并不试图在一个复杂的可订制的类中支持所有可预见的特征,相反可以定义一个简单的类,并且用Decorator类给他逐渐的添加功能,可以从简单的部件组合出复杂的功能。
    会产生比使用继承关系更多的对象,使得维护和排查问题略显复杂。

6、Decorator模式与Adapater、Builder模式的区别
    Adapter和Decorator模式的区别:
    前者关注的是如何将两个本来互不相关的但又有相似功能的类糅合到一起,后者关注的是如何在原来功能的基础上做一些小的调整。
    Builder和Decorator模式的区别:
    前者关注的是对象的构建,后者关注的是对象功能的添加、个性化。
    前者主要用于GUI界面构建对象的场合、后者主要用于动态添加功能、改变流程的场合。

posted on 2008-06-25 13:33 云淡风清 阅读(347) 评论(0)  编辑  收藏 所属分类: Design Patterns


只有注册用户登录后才能发表评论。


网站导航:
 
<2008年6月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

导航

统计

常用链接

留言簿(1)

随笔分类(15)

随笔档案(15)

收藏夹(1)

搜索

最新评论

阅读排行榜

评论排行榜