装饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
比如我们在买饼的这个场景里,就可以使用装饰者模式。我们可以只买一个饼(pie)手抓饼或鸡蛋饼,可以什么都不加,可以加鸡蛋(egg),培根(bacanic),生菜(lettuce),火腿肠(sausage)等等。在这里饼是需要装饰的对象,而鸡蛋等则是装饰品。
我们看一下装饰者模式的图例
component:公共组件,装饰品和装饰对象都继承于此。
concreteComponent:需要装饰的对象,扩展与component。
decorator:装饰品共同实现的接口,也可是抽象类。
concreteDecorator:装饰品,包含着一个component实例变量。
现在我们根据上面的图例来实现买手抓饼的场景。
首先定义component组件food类。
package sjms.decorator;
/**
* component
* @author dwl
*
*/
public abstract class Food {
//描述
String desc = "";
//返回描述
public String getDesc() {
return desc;
}
//计算价格,在子类中实现
public abstract double cost();
}
再定义装饰对象的Pie类。
package sjms.decorator;
/**
* concreteComponent
* 手抓饼
* @author dwl
*
*/
public class HandPie extends Food {
public HandPie() {
desc = "手抓饼";
}
//一个饼3元
@Override
public double cost() {
return 3.00;
}
}
package sjms.decorator;
/**
* concreteComponent
* 鸡蛋饼
* @author dwl
*
*/
public class EggPie extends Food {
public EggPie() {
desc = "鸡蛋饼";
}
//一个饼2.5元
@Override
public double cost() {
return 2.50;
}
}
配料的公共父类。
package sjms.decorator;
/**
* decorator
* 配料的抽象类,所有配料继承于此
* @author dwl
*
*/
public abstract class Condiment extends Food {
//子类重新实现该方法
public abstract String getDesc();
}
最后我们来写具体的配料鸡蛋生菜等。
package sjms.decorator;
/**
* concreteDecorator
* 鸡蛋
* @author dwl
*
*/
public class Egg extends Condiment {
//被装饰者
Food food;
public Egg(Food food){
this.food = food;
}
@Override
public String getDesc() {
return food.getDesc()+",鸡蛋";
}
//鸡蛋的价格加上被装饰者的价格
@Override
public double cost() {
return 1.00 + food.cost();
}
}
package sjms.decorator;
/**
* concreteDecorator
* 生菜
* @author dwl
*
*/
public class Lettuce extends Condiment {
//被装饰者
Food food;
public Lettuce(Food food){
this.food = food;
}
@Override
public String getDesc() {
return food.getDesc()+",生菜";
}
//生菜的价格加上被装饰者的价格
@Override
public double cost() {
return 1.50 + food.cost();
}
}
package sjms.decorator;
/**
* concreteDecorator
* 培根
* @author dwl
*
*/
public class Bacanic extends Condiment {
//被装饰者
Food food;
public Bacanic(Food food){
this.food = food;
}
@Override
public String getDesc() {
return food.getDesc()+",培根";
}
//培根的价格加上被装饰者的价格
@Override
public double cost() {
return 2.00 + food.cost();
}
}
装饰对象和装饰品都实现了,我们现在来看看买一个手抓饼加鸡蛋生菜培根怎么实现。
package sjms.decorator;
/**
* 买一个饼
* @author dwl
*
*/
public class BuyPie {
public static void main(String[] args) {
//老板,买一个手抓饼
Food pie = new HandPie();
System.out.println(pie.getDesc()+","+pie.cost()+"元");
//加一个鸡蛋吧
Food agg = new Egg(pie);
System.out.println(agg.getDesc()+","+agg.cost()+"元");
//加上生菜,营养均衡
Food lettuce = new Lettuce(agg);
System.out.println(lettuce.getDesc()+","+lettuce.cost()+"元");
//再加上培根,我喜欢吃肉
Food bacanic = new Bacanic(lettuce);
System.out.println(bacanic.getDesc()+","+bacanic.cost()+"元");
}
}
来看看控制台输出的结果。
总结:装饰者模式——利用对象组合,动态的将责任附加到对象上,扩展一个对象的功能。