某咖啡店因为扩张速度太快,需要更新订单系统
原先有一个Beverage(材料)抽象类,店内所提供的饮料都继承自它,有getDescription()、cost()和其他方法
有各种饮料,如HouseBlend,DarkRoast,Espresso等
而在购买咖啡时,也可以要求在其中加入各种调料,例如,Mocha,Soy,Whip等
这样一来组合就有很多种,如果每一种咖啡做成一个类,这简直就是类爆炸
有一个设计原则:类应该对扩展开放,对修改关闭
于是,我们可以使用Decorator Pattern,以饮料为主体,在运行时以调料来装饰饮料
比如,我想要一个加Mocha、Whip的DarkRoast咖啡,我们可以这么做:
1、拿一个DarkRoast对象
2、以Mocha对象装饰它
3、以Whip对象装饰它
4、调用cost()方法,并依赖委托(delegate)将调料的价钱加上去
上个类图:
代码:
从Beverage类下手
public abstract class Beverage {
String description="Unknown beverage";
public String getDescription(){
return description;
}
public abstract double cost();
}
Condiment抽象类,也就是装饰者类
public abstract class CondimentDecorator extends Beverage{
public abstract String getDescription();
}
实现一些饮料
public class Espresso extends Beverage{
public Espresso(){
description="Espresso";
}
public double cost(){
return 1.99;
}
}
public class DarkRoast extends Beverage{
public DarkRoast(){
description="DarkRoast";
}
public double cost(){
return 1.11;
}
}
public class HouseBlend extends Beverage{
public HouseBlend(){
description="HouseBlend";
}
public double cost(){
return .89;
}
}
实现具体装饰者,调料
public class Whip extends CondimentDecorator{
Beverage beverage;
public Whip(Beverage beverage){
this.beverage=beverage;
}
public String getDescription(){
return beverage.getDescription()+",Whip";
}
public double cost(){
return .25+beverage.cost();
}
}
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();
}
}
public class Soy extends CondimentDecorator{
Beverage beverage;
public Soy(Beverage beverage){
this.beverage=beverage;
}
public String getDescription(){
return beverage.getDescription()+",Soy";
}
public double cost(){
return .44+beverage.cost();
}
}
测试代码
public class Coffee {
public static void main(String[]args){
Beverage beverage=new Espresso();
System.out.println(beverage.getDescription()+" $"+beverage.cost());
Beverage beverage2=new DarkRoast();
beverage2=new Mocha(beverage2);
beverage2=new Soy(beverage2);
beverage2=new Whip(beverage2);
System.out.println(beverage2.getDescription()+" $"+beverage2.cost());
Beverage beverage3=new HouseBlend();
beverage3=new Soy(beverage3);
beverage3=new Mocha(beverage3);
beverage3=new Whip(beverage3);
System.out.println(beverage3.getDescription()+" $"+beverage3.cost());
}
结果
Espresso $1.99
DarkRoast,Mocha,Soy,Whip $2.0
HouseBlend,Soy,Mocha,Whip $1.78
----------------------------------------
其实IO就是装饰者
BufferedInputStream,LineNumberInputStream都扩展自FilterInputStream,而它就是一个抽象的装饰类
编写自己的IO装饰者
import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
public class LowerCaseInputStream extends FilterInputStream{
public LowerCaseInputStream(InputStream in){
super(in);
}
public int read()throws IOException{
int c=super.read();
return(c==-1?c:Character.toLowerCase((char)c));
}
public int read(byte[]b,int offset,int len)throws IOException{
int result=super.read(b, offset, len);
for(int i=offset;i<offset+result;i++){
b[i]=(byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public class InputTest {
public static void main(String[]args)throws IOException{
int c;
try{
InputStream in=new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("test.txt")));
while((c=in.read())>=0)
System.out.print((char)c);
in.close();
}catch(IOException e){e.printStackTrace();}
}
}
test.txt:I know the Decorator Pattern therefore I RULE!
结果:
i know the decorator pattern therefore i rule!
--------------------------------------- to conclude
Decorator Pattern动态的将责任附加到对象上,想要扩展功能,Decorator提供有别于继承的另一种选择。
在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。
Decorator会导致设计中出现许多小对象,如果过度使用,会让程序变得复杂。