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

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. 用运算符代替if、else

  2. TIF、JPG图片手动添加地理坐标的方法(转载)

    题目:为TIF.JPG图片添加地理坐标/平面直角坐标. 图片来源:GOOGLE EARTH.(当然也可以是其他知道四角点坐标的图片) 截图工具:GEtscreen(此软件截图时可以自动生成图片四角点坐 ...

  3. Python-json 和 pickle

    这是用于序列化的两个模块 json:用于字符串和python数据类型间进行转换 pickle:用于python特有的类型和python的数据类型间进行转换 json模块提供了四个功能:dumps du ...

  4. Eclipse添加注释简介

    (1)在方法或者属性上面添加注释:在方法或者属性字段的上面一行输/**,然后回车.一般情况下添加的注释格式如下所示,当然注释的格式是可以修改的:   1 2 3 4 5 /**   * @param ...

  5. C语言中的深拷贝和浅拷贝

    //C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...

  6. Photoshop Cc高级设计师培训视频教程(共109节课程)

    Photoshop Cc高级设计师培训视频教程(共109节课程) 专业培训Photoshop技能,其他网站收费内容,这里收集了,免费分享给你们哦~ 以下为部分截图: 下载地址: http://fu83 ...

  7. Java系列,《Java核心技术 卷1》,chapter 13,集合

    13.1.2 Java类库中的集合接口和迭代器接口     删除元素,对于next和remove的调用是互相依赖的,如果调用remove之前没有调用next,则会跑出IllegalStateExcep ...

  8. Spring MVC实现文件下载

     下载文件① 下载文件需要将byte数组还原成文件. 首先使用mybatis将数据库中的byte数组查出来,指定文件名(包括格式).然后使用OutputStream将文件输入 @RequestMapp ...

  9. 访问图片可以使用闭包map

    1 imageView.animationImages = [ UIImage(named:"panda1"), UIImage(named:"panda2") ...

  10. 『随笔』Socket 链接 必须 上下行 同时使用

    结论: > Socket 理论上 支持 只上行,或者 只下行. > 心跳包 必须是 上下行的 —— 心跳包请求(上行) - 心跳包响应(下行). > 如果 长时间 只有单向链接(只发 ...