TypeScript 设计模式之【装饰模式】
文章目录
- **装饰模式**:为你的对象穿上华丽的外衣
- 装饰者的魔法
- 装饰模式有什么利与害?
- 如何使用装饰者来美化你的对象
- 代码实现案例
- 装饰模式的主要优点
- 装饰模式的主要缺点
- 装饰模式的适用场景
- 总结
装饰模式:为你的对象穿上华丽的外衣
嘿程序员,你有一件普通格子衬衫,它很舒适,但有时候你可能想让它看起来更特别一些。你可以给它加上一些别针、徽章或者刺绣,让它变得与众不同。
这就像是在编程中使用装饰模式,你可以在不改变原始对象的情况下,为它添加新的功能或者修改它的行为。装饰模式就像是一位时尚设计师,能够为你的对象设计出各种华丽的"外衣"!
装饰者的魔法
装饰模式就像是给你的对象穿上一层又一层的"衣服",每一层都可以添加新的功能或者修改现有的行为,而且你可以随时添加或移除这些"衣服",非常灵活。
装饰模式有什么利与害?
装饰模式的优点是它可以在不修改原始代码的情况下扩展对象的功能,就像你可以给衬衫添加各种装饰而不需要改变衬衫本身。它遵循开闭原则,对扩展开放,对修改关闭。缺点是如果过度使用,会导致代码中出现大量小对象,使系统变得复杂难懂。
如何使用装饰者来美化你的对象
装饰涉及角色
-
组件(Component):定义可以动态添加职责的对象的接口
-
具体组件(ConcreteComponent):定义可以添加额外职责的对象
-
装饰(Decorator):维持一个指向Component对象的引用,并定义一个与Component接口一致的接口。
-
具体装饰(ConcreteDecorator):向组件添加职责。
装饰步骤
-
创建一个基础组件接口
-
实现具体的基础组件
-
创建一个装饰器基类,实现了组件接口并包含一个组件引用
-
创建具体的装饰器类,继承自装饰器基类并添加新的行为
-
使用这些装饰器来包装组件,从而动态地添加新的功能
选择合适的装饰器,你就能轻松地为你的对象添加各种功能,让它变得更加强大和灵活!
代码实现案例
// 组件接口-衬衫
interface Shirt {
// 获取外表
getDescription(): string;
// 获取成本
getCost(): number;
}
// 具体组件-普通衬衫
class BasicShirt implements Shirt {
getDescription(): string {
return "普通格子衬衫";
}
getCost(): number {
return 100;
}
}
// 装饰器基类
abstract class ShirtDecorator implements Shirt {
protected shirt: Shirt;
constructor(shirt: Shirt) {
this.shirt = shirt;
}
getDescription(): string {
return this.shirt.getDescription();
}
getCost(): number {
return this.shirt.getCost();
}
}
// 具体装饰器:别针
class PinDecorator extends ShirtDecorator {
getDescription(): string {
return `${this.shirt.getDescription()}, 加上别针`;
}
getCost(): number {
return this.shirt.getCost() + 20;
}
}
// 具体装饰器:徽章
class BadgeDecorator extends ShirtDecorator {
getDescription(): string {
return `${this.shirt.getDescription()}, 加上徽章`;
}
getCost(): number {
return this.shirt.getCost() + 15;
}
}
// 具体装饰器:刺绣
class EmbroideryDecorator extends ShirtDecorator {
getDescription(): string {
return `${this.shirt.getDescription()}, 加上刺绣`;
}
getCost(): number {
return this.shirt.getCost() + 50;
}
}
// 使用装饰器
let shirt: Shirt = new BasicShirt();
console.log(shirt.getDescription()); // 输出: 普通格子衬衫
console.log(shirt.getCost()); // 输出: 100
shirt = new PinDecorator(shirt);
console.log(shirt.getDescription()); // 输出: 普通格子衬衫, 加上别针
console.log(shirt.getCost()); // 输出: 120
shirt = new BadgeDecorator(shirt);
console.log(shirt.getDescription()); // 输出: 普通格子衬衫, 加上别针, 加上徽章
console.log(shirt.getCost()); // 输出: 135
shirt = new EmbroideryDecorator(shirt);
console.log(shirt.getDescription()); // 输出: 普通格子衬衫, 加上别针, 加上徽章, 加上刺绣
console.log(shirt.getCost()); // 输出: 185
装饰模式的主要优点
-
灵活性强:通过组合不同的装饰器来创建各种不同的行为
-
遵循开闭原则:在不修改现有代码的情况下添加新的功能
-
比继承更加灵活:动态地添加或删除职责,而不是在编译时就确定
-
支持递归组合:用多个装饰器包装一个组件
装饰模式的主要缺点
- 可能会创建很多小对象:每个装饰器都是一个新的对象,如果过度使用可能会导致系统变得复杂。
- 装饰层次增多时会更复杂:如果有太多的装饰类,或许会让系统变得难以理解和维护
- 可能会导致错误配置:由于可以动态地添加装饰器,或许会因为错误的配置导致意外的行为
装饰模式的适用场景
- 需要在运行时动态地给对象添加额外的职责,而不希望改变原有对象的结构
- 希望通过组合而不是继承来扩展对象的功能
- 系统中有大量独立的扩展,为支持每种组合将产生大量的子类,使得子类数目呈爆炸性增长。
总结
装饰模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。这种模式在不修改现有对象结构的情况下动态地扩展对象的功能,它具有很强的灵活性和可扩展性,但也会导致系统中出现大量小对象。合理使用装饰模式,可以让你的代码更加灵活,更易于维护和扩展。
喜欢的话就点个赞 ❤️,关注一下吧,有问题也欢迎讨论指教。感谢大家!!!
下期预告:TypeScript 设计模式之【外观模式】