一:定义:
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());
}
}
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();
}
}
}
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