设计模式之装饰者模式
1. 什么是装饰者模式
装饰( Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。
装饰者模式的结构如下图所示:
-
抽象组件角色: 一个抽象接口,是被装饰类和、装饰类的父接口。
-
具体组件角色:为抽象组件的实现类。
-
抽象装饰角色:包含一个组件的引用,并定义了与抽象组件一致的接口。
-
具体装饰角色:为抽象装饰角色的实现类。负责具体的装饰。
2. 简单实例
以一个简单的咖啡馆订单系统项目为例来一步步的介绍装饰者模式
咖啡馆订单项目:
1) 咖啡种类:Espresso、ShortBlack、LongBlack、Decaf
2) 调料:Milk、Soy、Chocolate
3) 扩展性好、改动方便、维护方便
首先按照我们的想法是:
就是设计一个Drink的类(咖啡的种类)然后在设计调料的类去扩展和组合,这样的话导致的问题就是我要添加新的调料的时候就需要添加很多的组合,这样的话就会导致添加很多的类,不容易维护和扩展
一个新的想法就是:
我重新设计下Drink类,调料直接添加在里面,然后设计咖啡类,每次添加调料的时候去查找有还是没有,然后进行添加,这样的话省掉了调料整合的问题,但是还是存在问题的,就是在添加新的调料的时候需要更新Drink这个类,这样其实也带来了扩展的不方便。
所以基于装饰者模式的思想,可以重新设计上面的项目,装饰者模式的设计思想其实可以看做是打包快递的过程,我要打包一件衣服,我需要包装袋和纸箱子,衣服就是主体,包装袋就是装饰,改变的时候就扩展包装就可以了。
重新设计的方案如上,Drink最为超类,然后咖啡去继承和扩展他,然后设计一个装饰者的类,去扩展Drink,然后调料的类去继承和扩展Decorator,这样的话每次更新调料,只需要添加新的继承自Decorator即可。下面给出具体的代码。
public abstract class Drink {
public String description="";
private float price=0f;
public void setDescription(String description)
{
this.description=description;
}
public String getDescription()
{
return description+"-"+this.getPrice();
}
public float getPrice()
{
return price;
}
public void setPrice(float price)
{
this.price=price;
}
public abstract float cost();
}
Coffee 作为一个中间层:
public class Coffee extends Drink {
@Override
public float cost() {
// TODO Auto-generated method stub
return super.getPrice();
}
}
public class Espresso extends Coffee{
public Espresso()
{
super.setDescription("Espresso");
super.setPrice(4.0f);
}
}
其他的咖啡同理…
public class Decorator extends Drink {
private Drink Obj;
public Decorator(Drink Obj){
this.Obj=Obj;
}
@Override
public float cost() {
// TODO Auto-generated method stub
return super.getPrice()+Obj.cost();
}
@Override
public String getDescription()
{
return super.description+"-"+super.getPrice()+"&&"+Obj.getDescription();
}
}
public class Chocolate extends Decorator {
public Chocolate(Drink Obj) {
super(Obj);
// TODO Auto-generated constructor stub
super.setDescription("Chocolate");
super.setPrice(3.0f);
}
}
其他的调料同理…
public static void main(String[] args) {
Drink order;
order=new Decaf();
System.out.println("order1 price:"+order.cost());
System.out.println("order1 desc:"+order.getDescription());
System.out.println("****************");
order=new LongBlack();
order=new Milk(order);
order=new Chocolate(order);
order=new Chocolate(order);
System.out.println("order2 price:"+order.cost());
System.out.println("order2 desc:"+order.getDescription());
}
}