装饰者模式 && ES7 decorator装饰器

装饰者模式

在提及这个新特性前我们先了解一下设计模式中的装饰者模式。

定义

装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对像动态的添加职责。与继承相比,装饰者是一种更轻便灵活的做法。

装饰者模式 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提供的方法,在浏览器中是无法直接运行的,所以我们需要提前作准备,对它进行编译。

  1. 安装基础插件
npm i babel-plugin-transform-decorators-legacy babel-register --save-dev

安装:
babel-plugin-transform-decorators-legacy 
babel-register

transform-decorators-legacy:
是第三方插件,用于支持decorators

babel-register:
用于接入node api
  1. 编写你的装饰器栗子decorator.js

  2. 创建compile.js

require('babel-register')({
    plugins: ['transform-decorators-legacy']
});
require("./decorator.js")
  1. 运行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}`);

参考文章

ECMAScript 6 入门

ES7 Decorator 装饰者模式

JavaScript设计模式----装饰者模式

es7-decorator修饰器实践

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容