一、简介
装饰者模式,顾名思义,即为原有的对象添加新的职责。装饰者模式在不修改底层代码给原有对象添加了新的功能,相比继承更加具有弹性。
装饰者模式特点:
- 具体被装饰者和装饰类都继承于相同的抽象类,继承的是类型,而不是行为。
- 可以使用多个装饰器装饰被装饰类。
- 由于被装饰类与装饰类具有同样的超类,因此能够用装饰后的对象代替原始对象。
- 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。
装饰者模式如下图所示,Component类为共同的超类,ConcreteComponent为被装饰类,Decorator为抽象装饰类,ConcreteDecoratorA/ConcreteDecoratorA为具体的装饰类,该类依赖Component类,并添加新方法,以添加新功能。
二、应用场景
当一个超类有不同的子类,同时不同的子类有不同的附加功能,这时可以考虑使用装饰者模式。在Java IO中有具体的应用,如下图所示:
三、具体应用
餐馆有2种食物,米饭和面条,可以加蛋、肉、大蒜,针对餐馆建立应用的类图如下所示:
源代码:
/** * 食物抽象类 */ public abstract class Food { protected String description = "This is a food"; public String getDescription() { return description; } public abstract double cost(); }
/** * 抽象装饰器类 * */ public abstract class SeasoningDecorator extends Food { protected Food food; public SeasoningDecorator(Food f) { food = f; } public abstract String getDescription(); }
具体的Component类,即被装饰类,rice和noodle
/** * 米饭类 */ public class Rice extends Food { public Rice(){ description ="This is rice"; } public double cost() { return 1; } }
/** * 面条 */ public class Noodle extends Food { public Noodle() { description = "This is noodle"; } public double cost() { return 8; } }
具体的装饰类
/** * 蛋 */ public class Egg extends SeasoningDecorator { public Egg(Food f){ super(f); } @Override public String getDescription() { return food.getDescription() + " with egg"; } @Override public double cost() { return food.cost() + 1.0; } }
/** * 肉 */ public class Meat extends SeasoningDecorator { public Meat(Food f) { super(f); } public String getDescription() { return food.getDescription() + " with meat"; } public double cost() { return food.cost() + 5.0; } }
/** * 大蒜 */ public class Garlic extends SeasoningDecorator { public Garlic(Food f) { super(f); } public String getDescription() { return food.getDescription() + " with garlic"; } public double cost() { return food.cost() + 2; } }
具体的测试类:
public class FoodTest { public static void main(String[] args) { Food f1 = new Rice(); f1 = new Meat(f1); f1 = new Egg(f1); System.out.println(f1.getDescription() + " $" + f1.cost()); Food f2 = new Noodle(); f2 = new Garlic(f2); f2 = new Egg(f2); f2 = new Egg(f2); System.out.println(f2.getDescription() + " $" + f2.cost()); } }
测试结果:
This is rice with meat with egg $7.0
This is noodle with garlic with egg with egg $12.0