ES7 Decorator 装饰者模式

415 查看

1、装饰模式

设计模式大家都有了解,网上有很多系列教程。

这里只分享 装饰者模式 以及如何使用 ES7 的 decorator 概念。

1.1、装饰模式 v.s. 适配器模式

装饰模式和适配器模式都是 包装模式 (Wrapper Pattern),它们都是通过封装其他对象达到设计的目的的,但是它们的形态有很大区别。

  • 适配器模式我们使用的场景比较多,比如连接不同数据库的情况,你需要包装现有的模块接口,从而使之适配数据库 —— 好比你手机使用转接口来适配插座那样;
  • 装饰模式不一样,仅仅包装现有的模块,使之 “更加华丽” ,并不会影响原有接口的功能 —— 好比你给手机添加一个外壳罢了,并不影响手机原有的通话、充电等功能;

更多区别参见:设计模式——装饰模式(Decorator)

1.2、装饰模式场景 —— 面向 AOP 编程

装饰模式经典的应用是 AOP 编程,比如“日志系统”,日志系统的作用是记录系统的行为操作,它在不影响原有系统的功能的基础上增加记录环节 —— 好比你佩戴了一个智能手环,并不影响你日常的作息起居,但你现在却有了自己每天的行为记录。

更加抽象的理解,可以理解为给数据流做一层filter,因此 AOP 的典型应用包括 安全检查、缓存、调试、持久化等等。可参考Spring aop 原理及各种应用场景 

2、使用 ES7 的 decorator

ES7 中增加了一个 decorator 属性,它借鉴自 Python,请参考文章Decorators in ES7

下面我们以 钢铁侠 为例讲解如何使用 ES7 的 decorator。

以钢铁侠为例,钢铁侠本质是一个人,只是“装饰”了很多武器方才变得那么 NB,不过再怎么装饰他还是一个人。

我们的示例场景是这样的

  • 首先创建一个普通的Man类,它的抵御值 2,攻击力为 3,血量为 3;
  • 然后我们让其带上钢铁侠的盔甲,这样他的抵御力增加 100,变成 102;
  • 让其带上光束手套,攻击力增加 50,变成 53;
  • 最后让他增加“飞行”能力

2.1、【Demo 1】对方法的装饰:装备盔甲

创建 Man 类

 

代码直接放在 http://babeljs.io/repl/ 中运行查看结果,记得勾选Experimental选项和Evaluate选项

创建 decorateArmour 方法,为钢铁侠装配盔甲——注意 decorateArmour 是装饰在方法init上的。

 

我们先看输出结果,防御力的确增加了 100,看来盔甲起作用了。

初学者这里会有两个疑问:

    1. decorateArmour方法的参数为啥是这三个?可以更换么?
    1. decorateArmour方法为什么返回的是descriptor

这里给出个人的解答作为参考:

  1. Decorators 的本质是利用了 ES5 的 Object.defineProperty 属性,这三个参数其实是和 Object.defineProperty 参数一致的,因此不能更改,详细分析请见 细说 ES7 JavaScript Decorators
  2. 可以看看 bable 转换后 的代码,其中有一句是 descriptor = decorator(target, key, descriptor) || descriptor; ,点到为止,这里不详细展开了,可自行看看这行代码的上下文(参考文献中也涉及到这句代码的解释)。

2.2、【Demo 2】装饰器叠加:增加光束手套

在上面的示例中,我们成功为 普通人 增加 “盔甲” 这个装饰;现在我想再给他增加 “光束手套”,希望额外增加 50 点防御值。

Step 1:拷贝一份decorateArmour方法,改名为decorateLight,同时修改防御值的属性: