设计模式之装饰器模式
2021 algorithmDecorator 装饰器模式。
装饰器模式主要解决继承关系过于复杂的问题,通过组合来替代继承。它主要的作用是给原始类添加增强功能。这也是判断是否该用装饰器模式的一个重要的依据。除此之外,装饰器模式还有一个特点,那就是可以对原始类嵌套使用多个装饰器。
为了满足这个应用场景,在设计的时候,装饰器类需要跟原始类继承相同的抽象类或者接口。
定义
动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator 模式比生成子类(继承)更为灵活(消除重复代码和减少子类个数)== 《设计模式》GoF
UML
几条原则
来自《Head First 设计模式》的几条原则。
- 装饰者和被装饰者对象有相同的超类型。
- 你可以用一个或多个装饰者包装一个对象。
- 既然装饰者和被装饰者对象有相同的超类型,所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。
- 装饰者可以在所委托被装饰者的行为之前或之后,加上自己的行为,以达到特定的目的。
- 对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
示例
interface Coffee {
public double getCost();
public String getIngredients();
}
class SimpleCoffee implements Coffee {
@Override
public double getCost() {
return 1;
}
public String getIngredients() {
return "Coffee";
}
}
abstract class CoffeeDecorator implements Coffee {
private final Coffee decoratedCoffee;
public CoffeeDecorator(Coffee c) {
this.decoratedCoffee = c;
}
@Override
public double getCost() {
return decoratedCoffee.getCost();
}
@Override
public String getIngredients() {
return decoratedCoffee.getIngredients();
}
}
class WithMilk extends CoffeeDecorator {
public WithMilk(Coffee c) {
super(c);
}
@Override
public double getCost() {
return super.getCost() + 0.5;
}
@Override
public String getIngredients() {
return super.getIngredients() + ", Milk";
}
}
class WithSprinkles extends CoffeeDecorator {
public WithSprinkles(Coffee c) {
super(c);
}
@Override
public double getCost() {
return super.getCost() + 0.2;
}
@Override
public String getIngredients() {
return super.getIngredients() + ", Sprinkles";
}
}
public class Main {
public static void printInfo(Coffee c) {
System.out.println("Cost: " + c.getCost() + "; Ingredients: " + c.getIngredients());
}
public static void main(String[] args) {
Coffee c = new SimpleCoffee();
printInfo(c);
c = new WithMilk(c);
printInfo(c);
c = new WithSprinkles(c);
printInfo(c);
}
}
// Cost: 1.0; Ingredients: Coffee
// Cost: 1.5; Ingredients: Coffee, Milk
// Cost: 1.7; Ingredients: Coffee, Milk, Sprinkles
要点总结
通过采用组合而非继承的手法,Decorator 模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
Decorator 类在接口上表现为 is-a Component 的继承关系,即 Decorator 类继承了 Component 类所具有的接口。但在实现上又表现为 has-a Component 的组合关系,即 Decorator 类又使用了另一个 Component 类。
Decorator 模式的目的并非解决“多子类衍生的多继承”问题,Decorator 模式应用的要点在于解决“主体类在多个方向上的扩展功能”–是为“装饰”的含义。
个人观点
装饰器模式是最能体现开放封闭原则的一种模式。
装饰器模式是组合优先于继承最直观的一种模式。
参考链接
- Wiki: Decorator pattern
- 《李建忠:C++设计模式》- 装饰模式