使用Decorator(装饰)模式改善现有软件设计—运行期给对象添加新功能

[quote]Decorator模式是一种结构型模式,它的作用是动态得给一个对象添加额外职责。Decorator模式,即Wrapper模式,其强制控制作用是在不改动一个类的代码或者不破坏一个类的接口的情况下为该类添加功能。当你想一个类具有更多功能的时候,使用Decorator模式意味着增加功能后的版本不一定要通过扩展类来重用现有功能。[/quote]

Decorator模式绝就绝在动态给对象添加新功能。一般我们使用继承的时候,行为是静态指定的,在没有编译前就指定了继承类(子类)可以做些什么。但是Decorator可以在运行时给定行为,是动态的。Decorator提供了比继承更有弹性的替代方案。

Decorator模式的重点就是类型匹配,装饰者与被装饰者之间必须有相同的超类。所以我们还是得使用继承。使用子类继承抽象基类。[color=red]我们这里去继承抽象类的目的不是为了继承它的行为,目的是为了有正确的类型,也就是类型的匹配。行为来自装饰者和基础组件,或与其它装饰者之间的引用关系。[/color]

为什么装饰者能动态的给对象添加新功能,原因就在这里,一般如果直接继承父类的话,那么我们的行为一定就会在编译之前就已经决定,这样一来,我们根本无法给对象添加新功能,但是使用了装饰者模式,我们又使用了对象与对象之间的组合,之后结果就完全不一样了。我们会写这样的代码:

File file=new File(path);    
BufferedReader br=new BufferedReader(new FileReader(file));


这个代码里面就是把file对象往FileReader里装,之后再把FileReader往BufferedReader装。进行一层一层的装饰。

装饰者模式有一套属于自己的设计思路。如下:


[img]http://dl.iteye.com/upload/attachment/169839/055fd802-abed-303d-a12f-c0a2be987e57.gif[/img]

Component(被装饰对象基类) :定义对象的接口(也可以是抽象类),可以给这些对象动态增加职责;
ConcreteComponent(具体被装饰对象) :定义具体的对象,Decorator可以给它增加额外的职责;
Decorator(装饰者抽象类): 维护一个指向Component实例的引用,并且定义了与Component一致的接口;
ConcreteDecorator(具体装饰者) :具体的装饰对象,给内部持有的具体被装饰对象增加具体的职责;

[quote]Decorator是装饰者模式里非常特殊的一个类,它既继承于Component【IS A关系】,又维护一个指向Component实例的引用【HAS A关系】,换个角度来说,Decorator跟Component之间,既有动态组合关系又有静态继承关系,WHY? 这里为什么要这么来设计?上面我们说过,组合的好处是可以在运行时给对象增加职责,Decorator【HAS A】Component的目的是让ConcreteDecorator可以在运行时动态给ConcreteComponent增加职责,这一点相对来说还比较好理解;那么Decorator继承于Component的目的是什么?在这里,继承的目的只有一个,那就是可以统一装饰者和被装饰者的接口,换个角度来说,不管是ConcretComponent还是ConcreteDecorator,它们都是 Component,用户代码可以把它们统一看作Component来处理,这样带来的更深一层的好处就是,装饰者对象对被装饰者对象的功能职责扩展对用户代码来说是完全透明的,因为用户代码引用的都是Component,所以就不会因为被装饰者对象在被装饰后,引用它的用户代码发生错误,实际上不会有任何影响,因为装饰前后,用户代码引用的都是Component类型的对象,这真是太完美了!装饰者模式通过继承实现统一了装饰者和被装饰者的接口,通过组合获得了在运行时动态扩展被装饰者对象的能力。

生活中的例子,俗话说“人在衣着马在鞍”,把这就话用装饰者模式的语境翻译一下,“人通过漂亮的衣服装饰后,男人变帅了,女人变漂亮了;”。对应上面的类图,这里人对应于ConcreteComponent,而漂亮衣服则对应于ConcreteDecorator;换个角度来说,人和漂亮衣服组合在一起【HAS A】,有了帅哥或美女,但是他们还是人【IS A】,还要做人该做的事情,但是可能会对异性更有吸引力了(扩展功能)! [/quote]

以下代码取自《HEAD FIRST 设计模式》。

Beverage还是所有饮料的基类,它对应于装饰者模式类图里的Component,是所有被装饰对象的基类;HouseBlend, DarkRoast, Espresso, Decaf是具体的饮料(咖啡)种类,对应于前面的ConcreteComponent,即是具体的被装饰对象;CondimentDecorator对应于前面的Decorator,是装饰者的抽象类;而Milk,Mocha,Soy,Whip则都是具体的调味品,对于前面的ConcreteDecorator,也就是具体的装饰者。

[img]http://dl.iteye.com/upload/attachment/169849/2da444e7-4c61-3836-8463-b2592062579e.jpg[/img]


package moshi.decorator;

public abstract class Beverage {

public String description="Unknown Beverage";

/*
* getDescription()已经在此实现了,但是cost()必须在子类中实现
*/
public String getDescription() {
return description;
}

public abstract double cost();
}

package moshi.decorator;

public abstract class CondimentDecorator extends Beverage {

//所有的调料装饰者都必须重新实现getDescription()方法.
public abstract String getDescription();

}

package moshi.decorator;

public class Espresso extends Beverage {

public Espresso(){
description="Espresso";
}


public double cost() {
return 1.99;
}

}


package moshi.decorator;

public class HouseBlend extends Beverage {

public HouseBlend(){
description="House Blend Coffee";
}


public double cost() {
return .89;
}

}


package moshi.decorator;

public class Mocha extends CondimentDecorator {

Beverage beverage;

public Mocha(Beverage beverage){
this.beverage=beverage;
}


public String getDescription() {
return beverage.getDescription()+"Mocha";
}


public double cost() {
return .20+beverage.cost();
}

}


package moshi.decorator;

public class Test {

public static void main(String[] args) {
Beverage beverae =new Espresso();
System.out.println(beverae.getDescription()+"$"+beverae.cost());


Beverage beverae1 =new Espresso();
beverae1 =new Mocha(beverae1);
beverae1 =new Mocha(beverae1);
System.out.println(beverae1.getDescription()+"$"+beverae1.cost());
}

}


这段代码很明显,说明了Decorator模式,就从Test类来看。
public static void main(String[] args) {
Beverage beverae =new Espresso();
System.out.println(beverae.getDescription()+"$"+beverae.cost());


Beverage beverae1 =new Espresso();
beverae1 =new Mocha(beverae1);
beverae1 =new Mocha(beverae1);
System.out.println(beverae1.getDescription()+"$"+beverae1.cost());
}


我们一开始只NEW了一个Espresso(),因为Espresso类继承了抽象Beverage类,实现了COST方法,我们自然打印出Espresso的钱。

之后,我们又NEW了一个Espresso(),这下情况有所不一样,我们使用了2个Mocha去往Espresso装饰对象,这里已经说名了下面这段代码为什么要取得Beverage引用。

public class Mocha extends CondimentDecorator {

Beverage beverage;

public Mocha(Beverage beverage){
this.beverage=beverage;
}


public String getDescription() {
return beverage.getDescription()+"Mocha";
}


public double cost() {
return .20+beverage.cost();
}

}


就因为我们取得了beverage,而且 cost()又实现了 return .20+beverage.cost();,自然返回的是Espresso+0.2的值了。


部分内容选自:http://www.cnblogs.com/justinw/archive/2007/06/11/779356.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值