InfoQ|你应该了解的5种TypeScript设计模式( 四 )

this.comp.move } } const dog = new Dog console.log("--- Non-decorated attempt: ") dog.move console.log("--- Flying decorator --- ") const superDog = new SuperAnimal(dog) superDog.move console.log("--- Now let's go swimming --- ") const swimmingDog = new SwimmingAnimal(dog) swimmingDog.move 注意一些细节:

  • 实际上 , SuperDecorator 类扩展了 Animal 类 , Dog 类也扩展了这个类 。 这是因为装饰器需要提供与其尝试装饰的类相同的公共接口 。
  • SuperDecorator 类是 abstract , 也就是说你实际上并没有使用它 , 只是用它来定义构造器 , 该构造器会将原始对象的副本保留在受保护的属性中 。 公共接口是在自定义装饰器内部完成覆盖的 。
  • SuperAnimal 和 SwimmingAnimal 是实际的装饰器 , 它们是添加额外行为的装饰器 。
这种设置的好处是 , 由于所有装饰器也间接扩展了 Animal 类 , 因此如果你要将两种行为混合在一起 , 则可以执行以下操作:
console.log("--- Now let's go SUPER swimming --- ") const superSwimmingDog = new SwimmingAnimal(superDog) superSwimmingDog.move如果你要使用经典继承 , 则动态结果会多得多 。
组合 最后来看组合模式 , 这是打包处理多个相似对象时非常有用且有趣的模式 。
这种模式使你可以将一组相似的组件作为一个组来处理 , 从而对它们执行特定的操作并汇总所有结果 。
这种模式的有趣之处在于 , 它不是一个简单的对象组 , 它可以包含很多实体或实体组 , 每个组可以同时包含更多组 。 这就是我们所说的树 。
看一个例子:
interface IProduct { getName: string getPrice: number } //The "Component" entity class Product implements IProduct { private price:number private name:string constructor(name:string, price:number) { this.name = name this.price = price } public getPrice: number { return this.price } public getName: string { return this.name } } //The "Composite" entity which will group all other composites and components (hence the "IProduct" interface) class Box implements IProduct { private products: IProduct = contructor { this.products = } public getName: string { return "A box with " + this.products.length + " products" } add(p: IProduct):void { console.log("Adding a ", p.getName, "to the box") this.products.push(p) } getPrice: number { return this.products.reduce( (curr: number, b: IProduct) => (curr + b.getPrice), 0) } } //Using the code... const box1 = new Box box1.add(new Product("Bubble gum", 0.5)) box1.add(new Product("Samsung Note 20", 1005)) const box2 = new Box


推荐阅读