javascript设计模式-装饰者

装饰者

基本实现

是一种为对象增加我的技术,它并不使用创建新子类手段,一切都在动态完成。这个过程相对于使用者来说是透明的。透明地把对象包装在具有同样接口的另一个对象之中。

比如可以动态的为自行车对象添加可选的特色配件上。比如添加4个选件,可以新定义4个超类,但如果自行车种类过多,则需要派生出N多子类。基本是不可以维护。如果用装饰者,只需要维护4个类即可,一个选件一个类。通过装饰加在各个原有的自行车上。

缺点在于,在遇到用装饰者包装起来的对象时,那些依赖于类型检查的代码会出问题,所以在设计此模式的类时不要使用类型检查。另外一点这种模式常常要引入许多小对象,它们看起来差不多,实际功能却大相径庭。所以使用此模式时要仔细,因为它的代码和API都不容易设计和使用。它的架构如下:

/* The Bicycle interface. */
var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'getPrice']);/* 自行车实例. */
var AcmeComfortCruiser = function() { };// implements Bicycle
AcmeComfortCruiser.prototype = {assemble: function() {},wash: function() {},getPrice: function() {return 399.00;}
};
/* 选件类,其实就是装饰者类,所有自行车和装饰者都需要实现Bicycle接口.装饰者模式颇多得益于接口的使用,其最重要的特点之一就是它可以用来替代组件,原来使用AcmeComfortCruiser的地方都可以用装饰类来代替而不用修改源代码,下面的装饰类对原类的两个方法进行了装饰。 * 下面的superclass是个自定义的属性,是在extends方法中加上的*/
var HeadlightDecorator = function(bicycle) { // implements BicycleHeadlightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
HeadlightDecorator.prototype.assemble = function() {return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function() {return this.bicycle.getPrice() + 15.00;
};
var myBicycle= newAcmeComfortCruiser();//裸自行车
var myBicycle = new TaillightDecorator(myBicycle); //加了一个篮子
myBicycle = new TaillightDecorator(myBicycle); //又加了另一个篮子
alert(myBicycle.getPrice());  //得到最终的价格

简单的组合模式和装饰者模式基本一样,但有些本质的区别,组合对象并不修改方法调用,其着眼于组织对象。而装饰者存在的唯一目的就是修改方法调用而不是组织子对象,因为子对象只有一个。

装饰者的作用在于以某种方式对其组件对象的行为进行修改。这种修改可以体现在方法之前、之后添加行为或是直接替换方法,甚至添加新的方法。

上例中一次只能添加一个选件,如果多个选件,需要多次调用即可。

HeadlightDecorator.prototype.getPrice = function() {return this.bicycle.getPrice() + 15.00;//之后};
var FrameColorDecorator = function(bicycle, frameColor) { //implements Bicyclethis.superclass.constructor(bicycle); // Call the superclass's constructor.this.frameColor = frameColor;
}
extend(FrameColorDecorator, BicycleDecorator); // Extend the superclass.FrameColorDecorator.prototype.assemble = function() {return 'Paint the frame ' + this.frameColor + ' and allow it to dry. ' + this.bicycle.assemble();//之前,注意这个参数的传递};
LifetimeWarrantyDecorator.prototype.repair = function() {return 'This bicycle is covered by a lifetime warranty. Please take it to ' +'an authorized Acme Repair Center.';
};//直接替换掉原来的方法实现

添加新方法时需要注意,因为接口中并没有声明,又不适合直接改接口,这样很多装饰子类中可能会有很多无用的代码,最好的方法是使用一种称为pass-through method的技术,暂时没搞清楚其运行机制。

OUTERLOOP:对组件对象进行检查 ,并为其拥有的每一个方法创建一个通道方法。这样在装饰类外再套上另一个装饰者的话,内层装饰者定义的新方法仍然可以访问。这样不用担心新创建的方法无法访问了。

var Bicycle = new Interface('Bicycle', ['assemble', 'wash', 'getPrice']);
/* 自行车实例. */
var AcmeComfortCruiser = function() { };// implements Bicycle
AcmeComfortCruiser.prototype = {assemble: function() {},wash: function() {},getPrice: function() {return 399.00;}
};
var BicycleDecorator = function(bicycle) { // implements Bicyclethis.bicycle = bicycle;this.interface = Bicycle;//这处会自动循环,通过另一种方式代替方法的调用,见最后    outerloop: for(var key in this.bicycle) {// Ensure that the property is a function.if(typeof this.bicycle[key] !== 'function') {continue outerloop;}for(var i = 0, len = this.interface.methods.length; i < len; i++) {if(key === this.interface.methods[i]) {continue outerloop;}}// Add the new method.var that = this;(function(methodName) {that[methodName] = function() {return that.bicycle[methodName]();};})(key);}
}
BicycleDecorator.prototype = {assemble: function() {return this.bicycle.assemble();},wash: function() {return this.bicycle.wash();},getPrice: function() {console.log('4');return this.bicycle.getPrice();}
};
var HeadlightDecorator = function(bicycle) { // implements BicycleHeadlightDecorator.superclass.constructor.call(this, bicycle);
}
extend(HeadlightDecorator, BicycleDecorator); // Extend the superclass.
HeadlightDecorator.prototype.assemble = function() {return this.bicycle.assemble() + ' Attach headlight to handlebars.';
};
HeadlightDecorator.prototype.getPrice = function() {console.log('3');return this.bicycle.getPrice() + 15.00;
};
var TaillightDecorator = function(bicycle) { // implements BicycleTaillightDecorator.superclass.constructor.call(this, bicycle);
}
extend(TaillightDecorator, BicycleDecorator); // Extend the superclass.
TaillightDecorator.prototype.assemble = function() {return this.bicycle.assemble() + ' Attach taillight to the seat post.';
};
TaillightDecorator.prototype.getPrice = function() {console.log('2');return this.bicycle.getPrice() + 9.00;
};
TaillightDecorator.prototype.ringBell = function() {console.log('1');return 'Bell rung.';
};
var c = new AcmeComfortCruiser();
c = new TaillightDecorator(c);
c = new HeadlightDecorator(c);
console.log(c.ringBell());//无论什么顺序都会调用console.log(c.getPrice());//423

有些时候装饰者的应用顺序很重要,但在理想情况下,装饰者应该能以一种完全与顺序无关的方式创建。如果必须要以某种顺序调用,可以结合工厂一般可以办到。某些装饰者修改组件方法的方式决定了它们需要最先或最后被应用,在此情况下工厂的作用就尤为重要。

函数装饰者

也可以用装饰者来装饰函数,通过把函数当作参数传递。在PYTHON语言中这是一个核心应用。它对函数的输出应用某种格式或执行某种转换方面非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/638590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

v35-36.problems

1.size of&#xff08;&#xff09;运算符 根据c语言标准规范&#xff0c;Size of&#xff08;&#xff09; 里面的操作数如果不是可变长度数组类型 &#xff0c;那么此操作数就不会被执行 &#xff01;

x-cmd pkg | skate - 个人键值对存储工具

目录 简介用户首次快速实验指南功能特点竞品和相关作品进一步探索 简介 skate 是个人键值对存储工具&#xff0c;具备数据加密、云端数据备份以及多设备同步等功能。 它由 Charm 团队开发&#xff0c;借用 Charm Cloud 向用户提供一种快捷的方式来保存和检索各种数据&#xf…

零基础学习【Linux】这一篇就够了

Linux学习目录 1. Linux简介1-1. Linux系统版本 2. Linux安装2-1. 安装方式2-2. Vmware安装2-3. Linux安装2-4. Vmware克隆2-5. Vmware快照2-6. 连接工具安装 3. Linux常用命令4. Linux软件安装5. 项目部署 1. Linux简介 1-1. Linux系统版本 Linux系统分为内核版和发行版 内核…

在线检测和离线检测的区别?

问题描述&#xff1a;在线检测和离线检测的区别&#xff1f; 问题解答&#xff1a; "在线检测"和"离线检测"是两种不同的数据或系统处理方式&#xff0c;主要区别在于处理的时机和方式&#xff1a; 在线检测&#xff08;Online Detection&#xff09;&am…

什么是UML?有什么用?

2、什么是UML?有什么用&#xff1f; UML 是 Unified Model Language的缩写&#xff0c;中文是统一建模语言&#xff0c;是由一整套图表组成的标准化建模语言。 UML 是一种统一建模语言&#xff0c;一种图标式语言&#xff08;画图的&#xff09; UML 不是只有 Java 中使用&…

Unity开发授权系统

Unity开发授权系统 引子 因为有些客户尾款到账不及时&#xff0c;因此研究了一套授权系统&#xff0c;当授权到期后&#xff0c;系统就提示软件授权已到期&#xff0c;不能继续使用云云&#xff0c;这样方便尾款的收回。 大体需求就是 时间相关性&#xff0c;可以自由设置授…

「斗破年番」大紫研爆虐六星斗皇,佛怒火连回归,异火焚烧分身

Hello,小伙伴们&#xff0c;我是拾荒君。 国漫《斗破苍穹年番》第80期超前爆料&#xff0c;据透露韩枫以海心焰这一异火贡献给了慕骨老人&#xff0c;换取了一具斗宗躯体。通过灵魂融入&#xff0c;他成功达到了斗宗四星阶段。而与小医仙对决的莫天行&#xff0c;尽管两人实力…

Java设计模式详解-更新中

收藏和关注的同时&#xff0c;请也关注 公众号 “IT技术馆” 各位大家好&#xff0c;从今天开始&#xff0c;作者开始整理 《JAVA软件设计模式&#xff08;GOF&#xff09;》 专栏。请各位多多关注&#xff01; 该专栏是根据作者的技术经验和设计模式的了解&#xff0c;进行详…

从零开始c++精讲:第三篇——内存管理

文章目录 一、C/C内存分布二、C语言中动态内存管理方式:malloc/calloc/realloc/free三、C中动态内存管理四、operator new与operator delete函数4.1 operator new与operator delete函数&#xff08;重点&#xff09; 五、new和delete的实现原理5.1内置类型5.2 自定义类型 六、定…

测试开源C#人脸识别模块ViewFaceCore(6:视频活体检测)

之前的文章介绍ViewFaceCore模块的FaceAntiSpoofing类支持单帧活体检测&#xff08;AntiSpoofing函数&#xff09;及视频活体检测&#xff08;AntiSpoofingVideo函数&#xff09;&#xff0c;视频活体检测时从摄像头中抓取一帧图片进行检测&#xff0c;当检测结果状态为Detecti…

使用阿里云服务器自建数据库配置多大合适?

阿里云服务器配置如何选择&#xff1f;用于自建数据库可以第七代云服务器ECS计算型c7、通用型g7或内存型r7实例&#xff0c;企业级独享型云服务器&#xff0c;CPU采用第三代Intel Xeon可扩展处理器&#xff08;Ice Lake&#xff09;&#xff0c;基频2.7 GHz&#xff0c;全核睿频…

MySQL中对日期时间的处理

⭕️前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(点击跳转到网站)⭕️ MySQL针对日期的处理 日期函数 SELECT CURDATE() -- 输出当前日期&#xff1a;2000-01-01 SELECT CURTIME() -- 输出当前时间&a…

代码随想录二刷 | 回溯 | 组合优化

代码随想录二刷 &#xff5c; 回溯 &#xff5c; 组合优化 剪枝优化 剪枝优化 在遍历的过程中有如下代码&#xff1a; for (int i startIndex; i < n; i) {path.pop_back();backtracking(n, k, i 1);path.pop_back(); }n 4&#xff0c;k 4的话&#xff0c;那么第一层f…

SpringMVC- ThreadLocal变量的注意点

基本介绍 在Web应用中&#xff0c;尤其是在使用Spring框架或类似的服务器端Java技术时&#xff0c;ThreadLocal 是一种常用的方式来存储每个请求的用户信息或上下文数据。然而&#xff0c;由于Web服务器通常使用线程池来处理请求&#xff0c;因此理解和正确使用ThreadLocal变得…

【Alibaba工具型技术系列】「EasyExcel技术专题」实战研究一下 EasyExcel 如何从指定文件位置进行读取数据

实战研究一下 EasyExcel 如何从指定文件位置进行读取数据 EasyExcel的使用背景EasyExcel的时候痛点EasyExcel对比其他框架 EasyExcel的编程模式EasyExcel读取的指定位置导入数据的流程表头校验invokeHeadMap()方法 数据处理invoke()方法 执行中断hasNextdoAfterAllAnalysed()方…

打折:阿里云国外服务器价格购买优惠活动

阿里云国外服务器优惠活动「全球云服务器精选特惠」&#xff0c;国外服务器租用价格24元一个月起&#xff0c;免备案适合搭建网站&#xff0c;部署独立站等业务场景&#xff0c;阿里云服务器网aliyunfuwuqi.com分享阿里云国外服务器优惠活动&#xff1a; 全球云服务器精选特惠…

idea 折叠某段代码 这段特定某段代码

如何折叠IntelliJ IDEA代码片段_w3cschool ctrlALTT

圆的参数方程是如何推导的?

圆的参数方程是如何推导的? 1. 圆的三种参数表示2. 三角函数万能公式3. 回到圆的参数方程1. 圆的三种参数表示 已知圆的第一种参数方程为: x 2 + y 2 = r x^2+y^2=r x2+y2=r   圆的图像如下: 通过上图,不难理解,圆的参数方程还可以用三角函数表示,也就是第二种参数表…

计算机毕业设计 | SpringBoot学生成绩管理系统(附源码)

1&#xff0c; 概述 1.1 课题背景 开发一个学生成绩管理系统&#xff0c;采用计算机对学生成绩进行处理&#xff0c;进一步提高了办学效益和现代化水平。为广大教师和学生提高工作效率&#xff0c;实现学生成绩信息管理工作流程的系统化、规范化和自动化。现在我国中学的学生…

基于STM32CubeMX创建FreeRTOS—以STM32F429为例

目录 1. 实验任务 2. 使用STM32CubeMX创建基础工程 2.1 打开STM32CubeMX 2.2 创建新项目 2.3 时钟设置 2.5 修改时钟基准&#xff0c;打开串行调试 2.6 配置串口 2.7 配置状态指示灯 2.8 FreeRTOS 2.9 配置工程输出项 3. 代码编辑 3.1 printf重映射 3.1.1 使用ARM…