无需原生开发基础,也能完美呈现京东商城。《混合开发京东商城系统,提前布局大前端》课程融合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
的引用,借助Phone
,Decorator
也拥有的打电话的功能call
,并且又提供了一个附加功能antiFall
,当我们执行Decorator
的call
方法的时候,它会调用Phone
的call
方法,完成打电话的功能,并会调用它自己的antiFall
方法完成它本身防止坠落的功能。
最后我们通过Client
来初始化了Phone
和Decorator
,并调用antiFall
方法。最终打印的结果为:
防止坠落
打电话
这样我们就通过Decorator
来为Phone
装饰上了一个新的功能。
使用场景
关于装饰器的使用场景,其最好的解释就是ES7
中Decorator
提案了,关于这块内容,阮一峰老师早在这里就做了详细的解释,我们在这里就不在去做一遍重复了,不过如果我们想要去使用 修饰器语法@Decorator
(我们后面会使用@Decorator
来表示修饰器语法) 的话,那么还需要额外做一些操作,这一块内容阮一峰老师并没有说,那么我们就在这里把使用@Decorator
的准备工作说一下,并且通过这个新的修饰器语法来把我们上面的项目进行一个改造,如果大家想要对@Decorator
语法进行更深的了解,那么可以点击这里。
因为@Decorator
为ES7
提案所以对想在的浏览器来说,绝大多数并不兼容,所以我们就需要使用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这个第三方类库了哈,其实这个类库就是一个很经典的装饰器使用方式。
首先装饰器模式不会改变被装饰类的现有结构。
其次装饰器模式是对被装饰类的现有功能的一个升级。
最后装饰器模式可以对被装饰类进行提供额外的注释功能。