装饰模式
装饰模式(Decorator Pattern)是一种结构型设计模式,它允许在不修改原始类的情况下动态地给对象添加功能。装饰模式通过创建一个包装对象(即装饰者),来包裹真实的对象,并在运行时动态地为这个对象添加新的行为或特性。
装饰模式的主要角色
- Component(组件接口):定义了被装饰的对象的接口,也可以是一个抽象类。
- ConcreteComponent(具体组件):实现了 Component 接口,是真正被装饰的对象。
- Decorator(装饰者):持有一个对 Component 对象的引用,并定义了一个与 Component 接口一致的接口。
- ConcreteDecorator(具体装饰者):扩展了 Component 的行为,通常会在操作前后执行一些额外的动作。
在 JavaScript 中的实现
下面是一个简单的例子来说明如何在 JavaScript 中使用装饰模式:
示例:咖啡店饮品定制系统
假设你正在开发一个咖啡店应用,客户可以定制自己的咖啡,比如添加牛奶、糖浆等。我们可以使用装饰模式来动态地增加这些选项。
javascript
// Component(组件接口)
class Beverage {
constructor() {
this.description = "Unknown Beverage";
}
getDescription() {
return this.description;
}
cost() {
throw new Error("This method should be overridden");
}
}
// ConcreteComponent(具体组件)
class Espresso extends Beverage {
constructor() {
super();
this.description = "Espresso";
}
cost() {
return 1.99;
}
}
// Decorator(装饰者)
class CondimentDecorator extends Beverage {
beverage;
constructor(beverage) {
super();
this.beverage = beverage;
}
getDescription() {
return this.beverage.getDescription();
}
}
// ConcreteDecorator(具体装饰者)
class Milk extends CondimentDecorator {
constructor(beverage) {
super(beverage);
}
getDescription() {
return this.beverage.getDescription() + ", Milk";
}
cost() {
return this.beverage.cost() + 0.1;
}
}
class Mocha extends CondimentDecorator {
constructor(beverage) {
super(beverage);
}
getDescription() {
return this.beverage.getDescription() + ", Mocha";
}
cost() {
return this.beverage.cost() + 0.2;
}
}
// 使用示例
let beverage = new Espresso();
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`); // 输出: Espresso $1.99
beverage = new Mocha(beverage);
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`); // 输出: Espresso, Mocha $2.19
beverage = new Milk(beverage);
console.log(`${beverage.getDescription()} $${beverage.cost().toFixed(2)}`); // 输出: Espresso, Mocha, Milk $2.29代码解释
- Beverage(组件接口):定义了饮料的基本属性和方法,包括获取描述和计算价格的方法。
- Espresso(具体组件):实现了
Beverage接口,表示具体的饮料类型——浓缩咖啡。 - CondimentDecorator(装饰者):作为所有装饰者的基类,持有对
Beverage对象的引用,并重写了getDescription方法。 - Milk 和 Mocha(具体装饰者):继承自
CondimentDecorator,分别代表向饮料中添加牛奶和摩卡的选项,并且各自增加了相应的费用。
应用场景
装饰模式适用于以下几种情况:
- 当需要在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责时。
- 当不能采用生成子类的方法进行扩充时,例如,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。
通过使用装饰模式,可以在不改变现有对象的情况下,灵活地为其添加新功能,这对于需求经常变化的应用程序特别有用。此外,装饰模式还支持递归组合,允许你构建复杂的装饰链,从而实现更强大的功能扩展。