JavaScript设计模式详解:06、装饰器模式

无需原生开发基础,也能完美呈现京东商城。《混合开发京东商城系统,提前布局大前端》课程融合vue、Android、IOS等目前流行的前端和移动端技术,混合开发经典电商APP——京东。课程将各种复杂功能与知识点完美融合,从技术原理到开发上线,让你真实感受到一个明星产品开发的全过程。功能实现之外,还有一流用户体验和优秀交互设计等你一探究竟,拓宽开发眼界。


什么是装饰器模式

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。

装饰器模式的定义就比较直白啦,就是对我们现有的一个类去添加了一个新的功能,但是呢,新的功能并不会改变这个类原先的结构。那怎么做呢?所以我们就需要去添加一个新的类,通过这个新的类来去为原有的类增加功能,这个新的类就是一个装饰类,也就是装饰器,这样一种模式,就是装饰器模式。

举例说明

知道了装饰器模式的定义之后,我们来看举例说明,装饰器模式的例子也很贴近生活,就比如我们的手机壳。

在这里插入图片描述

像这种手机壳,他并没有改变我们手机原有的功能,比如打电话,听音乐什么的。但却为手机提供了新的功能,比如后面的指环,这就是提供的新的功能。这就是一个典型的装饰器模式在生活中的例子。

绘制UML类图

然后我们就根据这个手机壳的实例,来绘制UML类图。

在这里插入图片描述

我们看一下绘制出来的UML类图,首先是Client代表是我们,我们有一个手机Phone,然后有一个手机壳作为手机的装饰器,我们叫他Decorator,这个main方法是一个入口函数,可以理解为我们对手机进行了一个打电话的操作,或者是对手机进行了一个使用的操作都可以。

然后手机拥有一个call方法,表示这个手机具有打电话的功能,然后装饰器Decorator它持有了一个手机的引用,所以它也具备了一个打电话的功能, 但是这个功能我们要知道它是借助手机Phone来完成的, 这个一定注意, 装饰器本身并没有被装饰类的功能,它是因为持有了被装饰类的引用,所以才具备了被装饰类的功能,其实这个功能还是通过被装饰类来完成的。 然后我们的装饰器对手机提供了一个新的功能antiFall,借助antiFall我们的手机具备了防止坠落的功能。

梳理完UML类图的逻辑之后,我们来看一下上面的这些内容,我们如何通过代码去实现。

代码实现

class Phone {
    call () {
        console.log('打电话');
    }
}

class Decorator {

    constructor (phone) {
        this.phone = phone;
    }

    call () {
        this.antiFall();
        this.phone.call();
    }

    antiFall () {
        console.log('防止坠落');
    }
}

class Client {
    constructor () {
        const phone = new Phone();
        this.decorator = new Decorator(phone);
    }

    main () {
        this.decorator.call();
    }
}

const client = new Client();
client.main();

我们来分析一下上面的代码,首先Phone具有一个打电话的功能call,当我们执行call方法的时候,会打印打电话这三字,然后有一个装饰器类Decorator,它持有Phone的引用,借助PhoneDecorator也拥有的打电话的功能call,并且又提供了一个附加功能antiFall,当我们执行Decoratorcall方法的时候,它会调用Phonecall方法,完成打电话的功能,并会调用它自己的antiFall方法完成它本身防止坠落的功能。

最后我们通过Client来初始化了PhoneDecorator,并调用antiFall方法。最终打印的结果为:

防止坠落
打电话

这样我们就通过Decorator来为Phone装饰上了一个新的功能。

使用场景

关于装饰器的使用场景,其最好的解释就是ES7Decorator 提案了,关于这块内容,阮一峰老师早在这里就做了详细的解释,我们在这里就不在去做一遍重复了,不过如果我们想要去使用 修饰器语法@Decorator (我们后面会使用@Decorator来表示修饰器语法) 的话,那么还需要额外做一些操作,这一块内容阮一峰老师并没有说,那么我们就在这里把使用@Decorator的准备工作说一下,并且通过这个新的修饰器语法来把我们上面的项目进行一个改造,如果大家想要对@Decorator语法进行更深的了解,那么可以点击这里

因为@DecoratorES7提案所以对想在的浏览器来说,绝大多数并不兼容,所以我们就需要使用babel对我们的代码进行一个转义。那么我们先通过npm来安装一下babel,我们执行 npm install --save-dev @babel/core babel-cli babel-preset-es2015, 然后如果我们想要babel能够识别@Decorator我们还需要安装babel-plugin-transform-decorators-legacy,我们执行npm install --save-dev babel-plugin-transform-decorators-legacy,最终我们的package.json的配置如下:

{
  "devDependencies": {
    "@babel/core": "^7.1.6",
    "babel-cli": "^6.26.0",
    "babel-plugin-transform-decorators-legacy": "^1.3.5",
    "babel-preset-es2015": "^6.24.1"
  }
}

然后我们创建一个.babelrc的文件,用以对babel完成基础配置,配置内容如下:

{
    "presets": [
        "es2015"
    ],
    "plugins": [
        "transform-decorators-legacy"
    ]
}

这些配置操作都完成之后,我们就是用@Decorator来重构一下我们的实例代码,我们在项目根目录下创建decorator.js,此时我们的项目目录如下:

- node_modules
- index.html
- .babelrc
- package-lock.json
- package.json
- decorator.js

然后我们来写一下decorator.js中的代码,使用@Decorator来重构我们的实例:


class Phone {
    @antiFall
    call () {
        console.log('打电话');
    }
}

function antiFall () {
    console.log('防止坠落');
}

let phone = new Phone();

phone.call();

在上面的代码中,我们就对call方法进行了一个装饰,装饰的方法就是antiFall,至于上面的代码什么意思,我就不再这里说了,我强烈推荐大家去看阮一峰老师关于ES7修饰器的文章。

然后我们可以通过npx babel decorator.js -o build.js 来把decorator.js编译成build.js,然后在index.html中引入build.js,代码的执行结果应该为:

防止坠落
打电话

总结

进入总结部分,装饰器我们会在什么情况下使用呢? 如果大家听了我的去看了阮一峰老师的文章,那么就应该直达了core-decorators这个第三方类库了哈,其实这个类库就是一个很经典的装饰器使用方式。

首先装饰器模式不会改变被装饰类的现有结构。
其次装饰器模式是对被装饰类的现有功能的一个升级。
最后装饰器模式可以对被装饰类进行提供额外的注释功能。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员Sunday

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值