使用装饰者模式做有趣的事情

 

什么是装饰者模式

装饰者模式是一种为函数或类增添特性的技术,它可以让我们在不修改原来对象的基础上,为其增添新的能力和行为。它本质上也是一个函数(在javascipt中,类也只是函数的语法糖)。

我们什么时候可以弄到它呢

我们来假设一个场景,一个自行车商店有几种型号的自行车,现在商店允许用户为每一种自行车提供一些额外的配件,比如前灯、尾灯、铃铛等。每选择一种或几种配件都会影响自行车的售价。

如果按照比较传统的创建子类的方式,就等于我们目前有一个自行车基类,而我们要为每一种可能的选择创建一个新的类。可是由于用户可以选择一种或者几种任意的配件,这就导致最终可能会生产几十上百个子类,这明显是不科学的。然而,对这种情况,我们可以使用装饰者模式来解决这个问题。

自行车的基类如下:

class Bicycle {     // 其它方法     wash () {}     ride () {}     getPrice() {         return 200;     } }

那么我们可以先创建一个装饰者模式基类

class BicycleDecotator {     constructor(bicycle) {         this.bicycle = bicycle;     }     wash () {         return this.bicycle.wash();     }     ride () {         return this.bicycle.ride();     }     getPrice() {         return this.bicycle.getPrice();     } }

这个基类其实没有做什么事情,它只是接受一个Bicycle实例,实现其对应的方法,并且将调用其方法返回而已。

有了这个基类之后,我们就可以根据我们的需求对原来的Bicycle类为所欲为了。比如我可以创建一个添加了前灯的装饰器以及添加了尾灯的装饰器:

class HeadLightDecorator extends BicycleDecorator {     constructor(bicycle) {         super(bicycle);     }     getPrice() {         return this.bicycle.getPrice() + 20;     } } class TailLightDecorator extends BicycleDecorator {     constructor(bicycle) {         super(bicycle);     }     getPrice() {         return this.bicycle.getPrice() + 20;     } }

那么,接下来我们就可以来对其自由组合了:

let bicycle = new Bicycle(); console.log(bicycle.getPrice()); // 200 bicycle = new HeadLightDecorator(bicycle); // 添加了前灯的自行车 console.log(bicycle.getPrice());  // 220 bicycle = new TailLightDecorator(bicycle); // 添加了前灯和尾灯的自行车 console.log(bicycle.getPrice()); // 240

这样写的好处是什么呢?假设说我们有10个配件,那么我们只需要写10个配件装饰器,然后就可以任意搭配成不同配件的自行车并计算价格。而如果是按照子类的实现方式的话,10个配件可能就需要有几百个甚至上千个子类了。

从例子中我们可以看出装饰者模式的适用场合:

  1. 如果你需要为类增添特性或职责,可是从类派生子类的解决方法并不太现实的情况下,就应该使用装饰者模式。
  2. 在例子中,我们并没有对原来的Bicycle基类进行修改,因此也不会对原有的代码产生副作用。我们只是在原有的基础上增添了一些功能。因此,如果想为对象增添特性又不想改变使用该对象的代码的话,则可以采用装饰者模式。

装饰者模式除了可以应用在类上之外,还可以应用在函数上(其实这就是高阶函数)。比如,我们想测量函数的执行时间,那么我可以写这么一个装饰器:

function func() {     console.log('func'); } function timeProfileDecorator(func) {     return function (...args) {         const startTime = new Date();         func.call(this, ...args);         const elapserdTime = (
                        
关键字:
50000+
5万行代码练就真实本领
17年
创办于2008年老牌培训机构
1000+
合作企业
98%
就业率

联系我们

电话咨询

0532-85025005

扫码添加微信