装饰器模式
装饰器(Decorator、Wrapper)模式属于结构型模式的一种。
装饰器模式是动态地给一个对象添加一些额外的职责。
装饰器模式的目的就是把一个一个的附加功能,给一层一层地累加在原始类上。
装饰器模式通常用于系统需要在运行时增加功能的场景,同时避免子类化和扩展原有类的复杂性。
装饰器本身可以继续装饰其他装饰器,从而形成装饰链。
装饰器模式提供了一种在运行时动态增加功能的方式,而无需修改原始对象的代码。
封装器是装饰模式的别称,封装器实现了与其封装对象相同的接口。我们可以将一个对象放入多个封装器中,并在对象中添加所有这些封装器的组合行为。
只要所有装饰都遵循相同的接口, 客户端就可以使用任意自定义的装饰来装饰对象。
在现实生活中,穿衣服就是使用装饰的一个例子。冷,可以穿秋裤,穿上秋裤还冷,可以穿毛裤,下雨还可以穿上雨衣。所有这些衣物都 “扩展” 了我们的基本行为, 但它们并不是我们的一部分, 如果我们不再需要某件衣物, 可以方便地随时脱掉。
装饰器模式通常有以下组成部分:
- Component(组件):定义一个接口或抽象类,所有具体组件和装饰器都必须遵循这个接口。
- ConcreteComponent(具体组件):实现了 Component 接口,定义了一个基础的对象,可以通过装饰器为其添加额外功能。
- Decorator(装饰器):实现了 Component 接口,持有一个 Component 对象的引用,并在 Component 的基础上添加额外功能。
- ConcreteDecorator(具体装饰器):具体的装饰器,继承自 Decorator,并且定义了具体的装饰行为,如改变行为。
使用装饰器模式来给咖啡添加牛奶和糖。
1、Component(组件)接口
// Component(组件)接口
interface Coffee {
double cost(); // 获取咖啡的价格
}
2、ConcreteComponent(具体组件)
// ConcreteComponent(具体组件)
class SimpleCoffee implements Coffee {
@Override
public double cost() {
return 5.0; // 基础咖啡的价格
}
}
3、Decorator(装饰器)类
// Decorator(装饰器)类,继承自 Coffee
abstract class CoffeeDecorator implements Coffee {
protected Coffee coffee; // 持有一个 Coffee 对象的引用
public CoffeeDecorator(Coffee coffee) {
this.coffee = coffee;
}
@Override
public double cost() {
return coffee.cost(); // 委托给被装饰的对象
}
}
4、ConcreteDecorator(具体装饰器)
// ConcreteDecorator(具体装饰器)- 添加牛奶
class MilkDecorator extends CoffeeDecorator {
public MilkDecorator(Coffee coffee) {
super(coffee); // 通过构造方法将原始对象传入
}
@Override
public double cost() {
return coffee.cost() + 1.0; // 加牛奶后,增加1元
}
}
// ConcreteDecorator(具体装饰器)- 添加糖
class SugarDecorator extends CoffeeDecorator {
public SugarDecorator(Coffee coffee) {
super(coffee); // 通过构造方法将原始对象传入
}
@Override
public double cost() {
return coffee.cost() + 0.5; // 加糖后,增加0.5元
}
}
5、客户端
// 测试装饰器模式
public class DecoratorPatternDemo {
public static void main(String[] args) {
Coffee simpleCoffee = new SimpleCoffee(); // 基础咖啡
System.out.println("Base Coffee cost: " + simpleCoffee.cost()); // 输出基础咖啡的价格
Coffee coffeeWithMilk = new MilkDecorator(simpleCoffee); // 加牛奶
System.out.println("Coffee with Milk cost: " + coffeeWithMilk.cost()); // 输出加牛奶后的价格
Coffee coffeeWithMilkAndSugar = new SugarDecorator(coffeeWithMilk); // 加糖
System.out.println("Coffee with Milk and Sugar cost: " + coffeeWithMilkAndSugar.cost()); // 输出加牛奶和糖后的价格
}
}
装饰器模式的优缺点。
优点:
- 把核心功能和附加功能分开了,两部分都可以进行独立地扩展。
- 增加功能的灵活性:能够在运行时动态地添加功能,而不需要修改现有代码。
- 避免子类化的繁琐:可以通过多层装饰器来组合功能,而无需通过继承产生大量的子类。
缺点:
- 多层装饰器导致复杂性增加:装饰器层级较多时,可能会导致系统结构复杂,调试和理解代码变得困难。
- 性能开销:每添加一个装饰器,都会增加一次方法调用的开销,尤其是在装饰器层级较多时,性能可能受到影响。
如果希望在无需修改代码的情况下即可使用对象,且希望在运行时为对象新增额外的行为, 可以使用装饰模式。
适配器能为被封装对象提供不同的接口,代理模式能为对象提供相同的接口,装饰则能为对象提供加强的接口。
不为障碍所困,紧盯目标;不为时间所迷,物尽其用;不为思维所限,向前一步。-- 烟沙九洲