装饰器模式

装饰者模式可以动态地给某个对象添加一些额外的职责,而不会影响从这个类中派生的其他对象。

这种给对象动态地增加职责的方式称为装饰者(decorator)模式。装饰者模式能够在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责。跟继承相比,装饰者是一种更轻便灵活的做法,这是一种“即用即付”的方式,比如天冷了就多穿一件外套,需要飞行时就在头上插一支竹蜻蜓,遇到一堆食尸鬼时就点开 AOE(范围攻击)技能。

优点

  • 装饰类和被装饰类都只关心自身的核心业务,实现了解耦。
  • 方便动态的扩展功能,且提供了比继承更多的灵活性。

缺点

  • 多层装饰比较复杂。
  • 常常会引入许多小对象,看起来比较相似,实际功能大相径庭,从而使得我们的应用程序架构变得复杂起来

举例:

class Cellphone {create() {console.log('生成一个手机')}
}
class Decorator {constructor(cellphone) {this.cellphone = cellphone}create() {this.cellphone.create()this.createShell(cellphone)}createShell() {console.log('生成手机壳')}
}
// 测试代码
let cellphone = new Cellphone()
cellphone.create()console.log('------------')
let dec = new Decorator(cellphone)
dec.create()

该例中,我们写了一个Decorator装饰器类,它重写了实例对象的create方法,给其方法新增了一个createShell(),因此最后为其输出结果进行了装饰。

例子2:

生活中的例子: 天气冷了, 就添加衣服来保暖;天气热了, 就将外套脱下;这个例子很形象地含盖了装饰器的神韵, 随着天气的冷暖变化, 衣服可以动态的穿上脱下。

let wear = function() {console.log('穿上第一件衣服')
}const _wear1 = wearwear = function() {_wear1()console.log('穿上第二件衣服')
}const _wear2 = wearwear = function() {_wear2()console.log('穿上第三件衣服')
}wear()// 穿上第一件衣服
// 穿上第二件衣服
// 穿上第三件衣服

这种方式有以下缺点: 1: 临时变量会变得越来越多;2: this 指向有时会出错

AOP 装饰函数

Function.prototype.before = function (beforefn) {var __self = this; // 保存原函数的引用return function () { // 返回包含了原函数和新函数的"代理"函数beforefn.apply(this, arguments); // 执行新函数,且保证this不被劫持,新函数接受的参数也会被原封不动地传入原函数,新函数在原函数之前执行return __self.apply(this, arguments); // 执行原函数并返回原函数的执行结果,并且保证this不被劫持}
}Function.prototype.after = function (afterfn) {var __self = this;return function () {var ret = __self.apply(this, arguments);afterfn.apply(this, arguments);return ret;}
};

Function.prototype.before接受一个函数当作参数,这个函数即为新添加的函数,它装载了新添加的功能代码。

接下来把当前的this保存起来,这个this指向原函数,然后返回一个“代理”函数,这个“代理”函数只是结构上像代理而已,并不承担代理的职责(比如控制对象的访问等)。它的工作是把请求分别转发给新添加的函数和原函数,且负责保证它们的执行顺序,让新添加的函数在原函数之前执行(前置装饰),这样就实现了动态装饰的效果。

我们注意到,通过Function.prototype.apply来动态传入正确的this,保证了函数在被装饰之后,this不会被劫持。

Function.prototype.after的原理跟Function.prototype.before一模一样,唯一不同的地方在于让新添加的函数在原函数执行之后再执行。

用AOP装饰函数实现上面的效果:

Function.prototype.before = function (beforefn) {var __self = this; // 保存原函数的引用return function () { // 返回包含了原函数和新函数的"代理"函数beforefn.apply(this, arguments); // 执行新函数,且保证this不被劫持,新函数接受的参数// 也会被原封不动地传入原函数,新函数在原函数之前执行return __self.apply(this, arguments); // 执行原函数并返回原函数的执行结果,// 并且保证this不被劫持}
}Function.prototype.after = function (afterfn) {var __self = this;return function () {var ret = __self.apply(this, arguments);afterfn.apply(this, arguments);return ret;}
};const wear1 = function() {console.log('穿上第一件衣服')
}const wear2 = function() {console.log('穿上第二件衣服')
}const wear3 = function() {console.log('穿上第三件衣服')
}const wear = wear1.after(wear2).after(wear3)
wear()// 穿上第一件衣服
// 穿上第二件衣服
// 穿上第三件衣服

值得注意的是,因为函数通过Function.prototype.before或者Function.prototype.after被装饰之后,返回的实际上是一个新的函数,如果在原函数上保存了一些属性,那么这些属性会丢失。代码如下:

var func = function(){console.log( 1 );
}
func.a = 'a';func = func.after( function(){console.log( 2 );
});console.log( func.a );   // 输出:undefined

【JavaScript设计模式】装饰器模式相关推荐

  1. Python设计模式-装饰器模式

    Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...

  2. Go 设计模式 - 装饰器模式

    装饰模式使用对象组合的方式动态改变或增加对象行为.Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式.使用匿名组合,在装饰器中不必显式定义转调原对象方法. 设计模式 装饰器模式 装饰器模式主要 ...

  3. Spring设计模式(装饰器模式)

    Spring设计模式(装饰器模式) 模式的定义: 装饰者模式定义: ​ 动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案. 模式的结构图 : 模式包含角 ...

  4. Java设计模式-装饰器模式 理论代码相结合

    继Java设计模式适配器模式后的装饰器模式来啦,让我们一起看看吧. 会了就当复习丫,不会来一起来看看吧. 很喜欢一句话:"八小时内谋生活,八小时外谋发展". 如果你也喜欢,让我们一 ...

  5. 设计模式--装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.简单来说,装饰器模式就是 ...

  6. PHP设计模式——装饰器模式

    声明:本系列博客参考资料<大话设计模式>,作者程杰. 装饰器模式又叫装饰者模式.装饰模式是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能.它是通过创建一个包装对象,也就是装 ...

  7. 设计模式-装饰器模式 C++

    一.简介 1.什么是装饰器模式 装饰器模式是结构型设计模式. 装饰器是现有类的一个包装,可以在不修改现有类且不增加子类的情况下扩展现有类. [注]可以实现向一个现有对象添加新的功能,同时又不改变其结构 ...

  8. 设计模式---装饰器模式(C++实现)

    装饰器模式(Decorator Pattern)允许向一个现有对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原 ...

  9. C++设计模式 装饰器模式

    文章目录 1. 先验知识 2. 装饰器模式相关概念 3. 装饰器模式的应用 3.1 应用1: 给形状添加新的特征 不同形状加红 3.2 应用2: 给一个人穿不同的衣服 a 直接person类, 增加穿 ...

  10. 白话设计模式-装饰器模式的使用和意义

    装饰器模式展示 在学习设计模式的过程中,将自己对于设计模式的理解,以最简单,最白话的方式,分享给大家.个人觉得,对于设计模式的理解,需要将他从最抽象的理论里,真实的代入到实际的业务场景中,将会有最深刻 ...

最新文章

  1. ASP.NET中常用的优化性能方法(转)
  2. python字典计数_Python下封装个好用计数字典包
  3. 使用C#进行系统编程
  4. django html显示xml,如何将HTML与Django集成?
  5. 抓住那头牛(信息学奥赛一本通-T1253)
  6. 原生语言开发web版万岳网校源码 v2.2.0
  7. 7_less中引入其他文件 / 模块
  8. 多线程之并发基础(四)
  9. 企业价值链与价值评价体系:88页华为绩效管理与绩效考核
  10. springMvc 乱码问题
  11. 自学python能干些什么副业-用Python赚钱的5个方法,教你业余时间赚外快!
  12. ERP管理web后台_数字化、智能化工厂管理系统原型、erp生产管理、仓库管理、采购管理、设备能源管理、计划管理、数字化工厂erp管理系统、生产计划、采购计划、用料请领、产品bom、工序管理、车间设备
  13. 易语言 查询API之文本和字体函数
  14. 三國演義與三國志兩部文本的導讀概要2019年5月11日
  15. 重启linux系统后 启动mysql ERROR! The server quit without updating PID file /var/run/mysqld/mysqld.pid
  16. MQX4.0:MK60DZ10.h头文件GPIO模块…
  17. uniapp使用逍遥模拟器调试项目
  18. asp数组函数LBound 、UBound和Split
  19. Ubuntu18.04如何安装汉语(拼音)输入法
  20. Redis集群(读写分离、哨兵机制、Cluster集群)

热门文章

  1. C#使用MathNet的矩阵与向量运算示例
  2. python urllib 函数_python的urllib.quote()和urllib.unquote()的等效javascript函数
  3. 2020年重磅喜讯!热烈祝贺王家林大咖大数据经典传奇著作《Spark大数据商业实战三部曲》 畅销书籍第二版 清华大学出版社发行上市! 前浪致 Spark + AI 后浪
  4. redis缓存hset, hget, hPutAll
  5. cmd中的%~dp0
  6. C++程序解线性一次方程组
  7. JS中的this指向
  8. 微星主板 B450 迫击炮 无线网卡 无法上网解决办法
  9. Android手机怎么找回微信好友,五种实用方法 安卓微信怎么恢复好友
  10. 第10章第4节:使用iSlide的统一色彩命令统一修改某个颜色 [PowerPoint精美幻灯片实战教程]