装饰模式:在不改变原类(对象)和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象。
在设计原则中,有一条,多用组合,少用继承,装饰模式正是这一原则的体现。

UML示意图:

假设自行车商店有4种自行车卖:

var ABicycle = function(){ ... };
var BBicycle = function(){ ... };
var CBicycle = function(){ ... };
var DBicycle = function(){ ... };

自行车商店需要给自行车加些配件,比如车筐,尾灯等,如果给每一类自行车创建一个子类:

var ABicycleWithBell = function(){ ... };
var BBicycleWithBasket = function(){ ... };
var CBicycleWithLight = function(){ ... };

带有铃铛的A类车,带有车筐的B类车,带有尾灯的C类车,导致的结果,就是N种配置会有4N个子类,当然不是一个可取的方法。
可以将铃铛等东西设置为实例属性,但是对于方法的扩展,比如变速等,就可以使用装饰模式。

A类自行车:

function ABicycle(){ }

ABicycle.prototype = {
wash : function(){ },
ride : function(){ },
getPrice : function(){
return 888;
}
}

铃铛:

function bicycleBell( bicycle ){
var price= bicycle.getPrice();
bicycle.bell = function(){
console.log("ding! ding!");
};
bicycle.getPrice = function(){
return price + 100;
};
return bicycle;
}

加铃铛:

var bicycleA = new ABicycle();
bicycleA = bicycleBell( bicycleA );

如果是:

bicycle.getPrice = function(){
return bicycle.getPrice() + 100;
};

会导致无限循环调用,换个方法:

function BicycleBell( bicycle ){
this.bicycle = bicycle;
} BicycleBell.prototype = {
wash : function(){
return this.bicycle.wash();
},
ride : function(){
return this.bicycle.ride();
},
getPrice : function(){
return this.bicycle.getPrice() + 100;
},
bell : function(){
console.log("ding! ding!");
}
}

包装对象,再次模拟原对象,这种方式较好的解决了对于某些需要修改并且依赖原始该方法的方法生成形式。但是有点繁琐,可以提取一下,通用继承函数:

function extend( subClass, superClass ){
var F = function(){};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
subClass.superclass = superClass.prototype;
if( superClass.prototype.constructor === Object.prototype.constructor ){
superClass.prototype.constructor = superClass;
}
}

装饰角色:

function BicycleDecorator( bicycle ){
this.bicycle = bicycle;
}
BicycleDecorator.prototype = {
wash : function(){
return this.bicycle.wash();
},
ride : function(){
return this.bicycle.ride();
},
getPrice : function(){
return this.bicycle.ride();
}
}

使用extend:

var BicycleBell = function( bicycle ){
BicycleBell.superclass.constructor.call( this, bicycle );
}
extend( BicycleBell, BicycleDecorator ); BicycleBell.prototype.bell = function(){
console.log("ding! ding!");
}
BicycleBell.prototype.getPrice = function(){
return this.bicycle.getPrice() + 100;
}

装铃铛:

var bicycleA = new ABicycle();
bicycleA = new BicycleBell( bicycleA );

装饰者模式是为已有功能动态地添加更多功能的一种方式,把每个要装饰的功能放在单独的函数里,然后用该函数包装所要装饰的已有函数对象,因此,当需要执行特殊行为的时候,调用代码就可以根据需要有选择地、按顺序地使用装饰功能来包装对象。优点是把类(构造函数)的核心职责和装饰功能区分开了。

javascript设计模式-装饰模式的更多相关文章

  1. JavaScript设计模式 -- 读书笔记

    JavaScript设计模式 一. 设计模式 一个模式就是一个可重用的方案: 有效的解决方法.易重用.善于表达该解决方案: 未通过"模式特性"测试的模式称为模式原型: 三规则:适用 ...

  2. 《JavaScript设计模式 张》整理

    最近在研读另外一本关于设计模式的书<JavaScript设计模式>,这本书中描述了更多的设计模式. 一.创建型设计模式 包括简单工厂.工厂方法.抽象工厂.建造者.原型和单例模式. 1)简单 ...

  3. 《JavaScript设计模式与开发实践》整理

    最近在研读一本书<JavaScript设计模式与开发实践>,进阶用的. 一.高阶函数 高阶函数是指至少满足下列条件之一的函数. 1. 函数可以作为参数被传递. 2. 函数可以作为返回值输出 ...

  4. Javascript设计模式学习一

    学习Javascript设计模式之前,需要先了解一些相关知识,面向对象的基础知识.this等重要概念,以及掌握一些函数式编程的技巧. Js多态 多态的思想:实际上是把“做什么”和“谁去做”分离开来.例 ...

  5. javascript设计模式实践之职责链--具有百叶窗切换图片效果的JQuery插件(三)

    在上一篇<javascript设计模式实践之模板方法--具有百叶窗切换图片效果的JQuery插件(二)>里,通过采用模板方法模式完成了切换效果对象的构建编写. 接下来就是完成各效果对象的调 ...

  6. javascript设计模式实践之模板方法--具有百叶窗切换图片效果的JQuery插件(二)

    在上一篇<javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)>里,通过采用迭代器模式完成了各初始化函数的定义和调用. 接下来就要完成各个切换效果的编 ...

  7. javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)

    类似于幻灯片的切换效果,有时需要在网页中完成一些图片的自动切换效果,比如广告,宣传,产品介绍之类的,那么单纯的切就没意思了,需要在切换的时候通过一些效果使得切换生动些. 比较常用之一的就是窗帘切换了. ...

  8. 常用的Javascript设计模式

    <parctical common lisp>的作者曾说,如果你需要一种模式,那一定是哪里出了问题.他所说的问题是指因为语言的天生缺陷,不得不去寻求和总结一种通用的解决方案. 不管是弱类型 ...

  9. Javascript设计模式(摘译)

    说明: 未完成...更新中.... 一.javascipt设计模式分类 设计模式分类有很多标准,最流行的三种如下 1)  creational  --  主要关注对象创建 Creational des ...

随机推荐

  1. js 日期2015/12/22/16/45替换2015-12-22 16:45格式

    js 日期2015/12/22/16/45替换2015-12-22 16:45格式 利用正则分组: function toChange(date) { var reg = /(\d+)\/(\d+)\ ...

  2. windows客户机连接gerrit的一个报错处理

    gerrit环境部署在linux服务器,windos客户机连接gerrit进行代码操作: 在windows客户机下载Git客户端 在“Git Bash”里使用 ”ssh-keygen -t rsa - ...

  3. final-----finalize----finally---区别

    一.性质不同 (1)final为关键字: (2)finalize()为方法: (3)finally为为区块标志,用于try语句中: 二.作用 (1)final为用于标识常量的关键字,final标识的关 ...

  4. Git之分支创建策略

    分支策略:git上始终保持两个分支,master分支与develop分支.master分支主要用于发布时使用,而develop分支主要用于开发使用. 创建master的分支developgit che ...

  5. 通过spring,在项目的任意位置获取当前Request

    需要引入: import javax.servlet.http.HttpServletRequest; import org.springframework.web.context.request.R ...

  6. Android调用基于.net的WebService

    在实际开发项目中,有时候会为Android开发团队提供一些接口,一般是以asmx文件的方式来承载.而公布出去的数据一般上都是标准的json数据.但是在实际过程中,发现Android团队那边并不是通过将 ...

  7. 即学即会 Java 程序设计基础视频教程(100课整)无水印版

    课程总共包含100个课时,总授课长达27多个小时,内容覆盖面广,从入门到精通,授课通俗易懂,分析问题独到精辟通过本套视频的学习,学员能够快速的掌握java编程语言,成为java高手. 课程目录:课时1 ...

  8. qt中文乱码问题

    首先,声明一下,QString 是不存在中文支持问题的,很多人遇到问题,并不是本身 QString 的问题,而是没有将自己希望的字符串正确赋给QString. 很简单的问题,"我是中文&qu ...

  9. Android权限列表permission说明

    网络上不乏android权限列表,但是很少有将列表和使用方法放在一起的,所以特此总结一下 需要在AndroidManifest.xml中定义相应的权限(以获取internet访问权限为例),如下: & ...

  10. 20135202闫佳歆--week 8 进程的切换和系统的一般执行过程--学习笔记

    此为个人笔记存档 week 8 进程的切换和系统的一般执行过程 一.进程调度与进程切换 1.不同的进程有不同的调度需求 第一种分类: I/O密集型(I/O-bound) 频繁的进行I/O 通常会花费很 ...