装饰器模式
装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许向一个现有的对象添加新的功能,同时又不改变其结构。这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
主要特点
- 装饰器模式通过组合而非继承来扩展对象的功能
- 可以动态地添加或删除对象的职责
- 遵循开闭原则,对扩展开放,对修改关闭
- 支持递归组合,可以创建多层装饰
适用场景
- 需要在运行时动态地给对象添加额外的职责
- 不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展维护的情况
代码示例
在示例中,我们将创建一个咖啡订单系统。基础咖啡可以添加不同的配料(装饰器),如牛奶、糖、奶泡等,每种配料都会增加一定的成本。
ts
// 咖啡接口
interface Coffee {
getCost(): number;
getDescription(): string;
}
// 基础咖啡类
class SimpleCoffee implements Coffee {
getCost(): number {
return 10;
}
getDescription(): string {
return "简单咖啡";
}
}
// 装饰器基类
abstract class CoffeeDecorator implements Coffee {
protected coffee: Coffee;
constructor(coffee: Coffee) {
this.coffee = coffee;
}
getCost(): number {
return this.coffee.getCost();
}
getDescription(): string {
return this.coffee.getDescription();
}
}
// 具体装饰器:牛奶
class MilkDecorator extends CoffeeDecorator {
getCost(): number {
return this.coffee.getCost() + 2;
}
getDescription(): string {
return this.coffee.getDescription() + ", 加牛奶";
}
}
// 具体装饰器:糖
class SugarDecorator extends CoffeeDecorator {
getCost(): number {
return this.coffee.getCost() + 1;
}
getDescription(): string {
return this.coffee.getDescription() + ", 加糖";
}
}
// 具体装饰器:奶泡
class WhipDecorator extends CoffeeDecorator {
getCost(): number {
return this.coffee.getCost() + 3;
}
getDescription(): string {
return this.coffee.getDescription() + ", 加奶泡";
}
}
// 使用示例
let coffee: Coffee = new SimpleCoffee();
console.log(coffee.getDescription()); // 输出:简单咖啡
console.log(coffee.getCost()); // 输出:10
// 加牛奶
coffee = new MilkDecorator(coffee);
console.log(coffee.getDescription()); // 输出:简单咖啡, 加牛奶
console.log(coffee.getCost()); // 输出:12
// 加糖
coffee = new SugarDecorator(coffee);
console.log(coffee.getDescription()); // 输出:简单咖啡, 加牛奶, 加糖
console.log(coffee.getCost()); // 输出:13
// 加奶泡
coffee = new WhipDecorator(coffee);
console.log(coffee.getDescription()); // 输出:简单咖啡, 加牛奶, 加糖, 加奶泡
console.log(coffee.getCost()); // 输出:16
实现分析
基础组件:
Coffee
接口定义了基本的行为:获取成本和描述SimpleCoffee
类实现了基本的咖啡,提供了基础价格和描述
装饰器基类:
CoffeeDecorator
是所有装饰器的抽象基类- 它实现了
Coffee
接口,并持有一个被装饰的Coffee
对象 - 默认情况下,它会将所有操作委托给被装饰的对象
具体装饰器:
MilkDecorator
:为咖啡添加牛奶,价格 +2SugarDecorator
:为咖啡添加糖,价格 +1WhipDecorator
:为咖啡添加奶泡,价格 +3- 每个装饰器都扩展了基础功能,增加了自己的价格和描述
动态性:
- 装饰器可以动态组合,顺序不限
- 每个装饰器都保持了接口的一致性
- 可以随时添加新的装饰器而不影响现有代码
优点
- 比继承更灵活,对象的功能可以动态增强
- 遵循单一职责原则,每个装饰器专注于一个功能
- 遵循开闭原则,可以在不修改现有代码的情况下添加新功能
- 装饰类和被装饰类可以独立发展,互不耦合
缺点
- 使用装饰器模式会产生很多小对象,增加系统的复杂度
- 装饰器模式会导致设计中出现许多相似的类
- 装饰器顺序不同可能导致不同的结果
装饰器模式的示例
咖啡订单系统
基础咖啡
价格: 10元
描述: 简单咖啡
添加配料
当前咖啡
总价: 10元
描述: 简单咖啡
日志输出