装饰者模式
在提及这个新特性前我们先了解一下设计模式中的装饰者模式。
定义
装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。
装饰者模式 v.s. 适配器模式
装饰者模式和适配器模式都是包装模式 (Wrapper Pattern),它们都是通过封装其他对象达到设计的目的的,但是它们的形态有很大区别。
适配器模式我们使用的场景比较多,比如连接不同数据库的情况,你需要包装现有的模块接口,从而使之适配数据库 —— 好比你手机使用转接口来适配插座那样;
装饰者模式不一样,仅仅包装现有的模块,使之 “更加华丽” ,并不会影响原有接口的功能 —— 好比你给手机添加一个外壳罢了,并不影响手机原有的通话、充电等功能;
装饰者模式使用场景
AOP(面向切面编程)
使用场景:安全检查、缓存、调试、持久化
封装before/after函数
封装axios添加参数,鉴权,错误监听等功能
为表单提交添加验证函数
装饰器decorator
装饰器可以改变类的行为,也可以改变方法的行为。
装饰器不能用于函数,因为存在函数提升问题。
装饰器接受三个参数,因为它本质上是利用了 ES5 的 Object.defineProperty 属性,这三个参数其实是和 Object.defineProperty 参数一致的,因此不能更改。
第一个参数是要装饰的对象target
第二个参数是对象的属性名key
第三个参数是该属性的描述对象descriptor
// descriptor对象{ value: specifiedFunction, enumerable: false, configurable: true, writable: true};
如果同一个方法有多个修饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行。
立即开始
由于decorator是es7提供的方法,在浏览器中是无法直接运行的,所以我们需要提前作准备,对它进行编译。
安装基础插件
npm i babel-plugin-transform-decorators-legacy babel-register --save-dev 安装: babel-plugin-transform-decorators-legacy babel-registertransform-decorators-legacy: 是第三方插件,用于支持decorators babel-register: 用于接入node api
编写你的装饰器栗子decorator.js
创建compile.js
require('babel-register')({ plugins: ['transform-decorators-legacy'] });require("./decorator.js")
运行compile.js
node compile
一个decorator栗子
// 主食加餐-方法装饰器function addMeat(target, key, descriptor) { const method = descriptor.value; let ret; descriptor.value = (...args) => { args[0] = '鳗鱼炒饭'; ret = method.apply(target, args); return ret; } return descriptor }// 饮料加餐-方法装饰器function addDrink(target, key, descriptor) { const method = descriptor.value; let ret; descriptor.value = (...args) => { args[1] = '莫吉托'; ret = method.apply(target, args); return ret; } return descriptor }// 新增甜品-类装饰器function addDimSum(isAdd) { return function(target) { target.isAdd = isAdd; let extra = isAdd ? ' (加餐加餐!另送一份拿破仑蛋糕' : ''; let method = target.prototype.toString; target.prototype.toString = (...args) => { return method.apply(target.prototype, args) + extra } return target } } @addDimSum(true)class Dinner { constructor(meat, drink) { this.init(meat, drink); } @addMeat @addDrink init (meat, drink) { this.meat = meat; this.drink = drink } toString () { return `今日特价晚餐:${this.meat} 配 ${this.drink}`; } }let todayDinner = new Dinner('白饭', '白开水');console.log(`${todayDinner}`);
自己实现一个decorator
// 创建一个基类function Dinner () { this.meat = '白饭'; this.drink = '白开水'; } Dinner.prototype.toString = function () { return `今日特价晚餐:${this.meat} 配 ${this.drink}`; }// 创建一个装饰器var Decorator = function (dinner) { this.dinner = dinner; } Decorator.prototype.toString = function () { return this.dinner.toString(); }// 继承装饰器var AddMeat = function (dinner) { dinner.meat = '鳗鱼草饭'; Decorator.call(this, dinner); } AddMeat.prototype = new Decorator(); AddMeat.prototype.toString = function () { return this.dinner.toString(); }// 实例var todayDinner = new Dinner('白饭'); todayDinner = new AddMeat(todayDinner);console.log(`${todayDinner}`);
作者:Eason_Wong
链接:https://www.jianshu.com/p/605d822a95db
共同学习,写下你的评论
评论加载中...
作者其他优质文章