一:定義:
Decorator:Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.
二:引入
假設現在有一家咖啡店,經營咖啡,茶等飲料,我們來為它設計一個系統。
問題:
- 飲料加糖或牛奶等調料時是要另收費的(每包1元),顧客可以要也可以不要,是以這個固定價格的cost方法不符合要求. 不符合OCP(open for extension,close for modification)
重新設計:
很顯然,這種設計也不合适,會導緻
- 類數量爆炸性增長(class exploson).
- 也不符合要求,比如有的顧客要兩包糖等情況沒有考慮到.
引入Decorator設計模式:
public abstract class Beverage ... {
private String discription;
public String getDiscription() ...{
return discription;
}
public void setDiscription(String discription) ...{
this.discription = discription;
}
public abstract double cost() ;
}
public class Coffee extends Beverage ... {
public Coffee()
...{
setDiscription("coffee");
}
public double cost()
...{
return 10;
}
}
public abstract class CondimentDecorator extends Beverage ... {
public abstract String getDiscription() ;
}
public class CondimentMilk extends CondimentDecorator ... {
private Beverage beverage;
public CondimentMilk(Beverage beverage)
...{
this.beverage=beverage;
}
public double cost()
...{
return beverage.cost()+1;
}
public String getDiscription()
...{
return beverage.getDiscription()+",milk";
}
}
public class Client ... {
public static void main(String args[])
...{
Beverage coffee=new Coffee();
System.out.println(coffee.getDiscription()+":"+coffee.cost());
System.out.println(new CondimentMilk(coffee).getDiscription()+":"+new CondimentMilk(coffee).cost());
System.out.println(new CondimentSugar(new CondimentMilk(coffee)).getDiscription()+":"+new CondimentSugar( new CondimentMilk(coffee)).cost());
System.out.println(new CondimentSugar(new CondimentSugar(new CondimentMilk(coffee))).getDiscription()+":"+new CondimentSugar(new CondimentSugar( new CondimentMilk(coffee))).cost());
}
}
三:結構
四:實際應用
- JAVA I/O 系統是decorator模式的典型應用
我們自己來寫一個InputStream decorator,用來使所有的輸出字元變成小寫.
public class LowerCaseInputStream extends FilterInputStream ... {
protected LowerCaseInputStream(InputStream in) ...{
super(in);
}
public int read() throws IOException
...{
int c=super.read();
return (c==-1?c:Character.toLowerCase(c));
}
}
public class IoTest ... {
public static void main(String args[]) ...{
int c;
String filePath = "f:/temp/designPatten.txt";
try ...{
InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream(
filePath)));
while(( c=in.read())!=-1)
...{
System.out.print((char)c);
}
in.close();
} catch (FileNotFoundException e) ...{
e.printStackTrace();
} catch (IOException e) ...{
e.printStackTrace();
}
}
}
五:适用情形
Use Decorator
- to add responsibilities to individual objects dynamically and transparently, that is, without affecting other objects.
- for responsibilities that can be withdrawn.
- when extension by subclassing is impractical. Sometimes a large number of independent extensions are possible and would produce an explosion of subclasses to support every combination. Or a class definition may be hidden or otherwise unavailable for subclassing.
參考文獻:
1:閻宏,《Java與模式》,電子工業出版社
2:Eric Freeman & Elisabeth Freeman,《Head First Design Pattern》,O'REILLY