深入理解JavaScript系列(29):设计模式之装饰者模式详解


Posted in Javascript onMarch 03, 2015

介绍

装饰者提供比继承更有弹性的替代方案。 装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数)。

装饰者用于通过重载方法的形式添加新功能,该模式可以在被装饰者前面或者后面加上自己的行为以达到特定的目的。

正文

那么装饰者模式有什么好处呢?前面说了,装饰者是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,而装饰者却不然。取而代之的是它能给不同对象各自添加新行为。如下代码所示:

//需要装饰的类(函数)

function Macbook() {

    this.cost = function () {

        return 1000;

    };

}
function Memory(macbook) {

    this.cost = function () {

        return macbook.cost() + 75;

    };

}
function BlurayDrive(macbook) {

    this.cost = function () {

        return macbook.cost() + 300;

    };

}


function Insurance(macbook) {

    this.cost = function () {

        return macbook.cost() + 250;

    };

}


// 用法

var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook())));

console.log(myMacbook.cost());

下面是另一个实例,当我们在装饰者对象上调用performTask时,它不仅具有一些装饰者的行为,同时也调用了下层对象的performTask函数。

function ConcreteClass() {

    this.performTask = function () {

        this.preTask();

        console.log('doing something');

        this.postTask();

    };

}
function AbstractDecorator(decorated) {

    this.performTask = function () {

        decorated.performTask();

    };

}
function ConcreteDecoratorClass(decorated) {

    this.base = AbstractDecorator;

    this.base(decorated);
    decorated.preTask = function () {

        console.log('pre-calling..');

    };
    decorated.postTask = function () {

        console.log('post-calling..');

    };
}
var concrete = new ConcreteClass();

var decorator1 = new ConcreteDecoratorClass(concrete);

var decorator2 = new ConcreteDecoratorClass(decorator1);

decorator2.performTask();

再来一个彻底的例子:

var tree = {};

tree.decorate = function () {

    console.log('Make sure the tree won\'t fall');

};
tree.getDecorator = function (deco) {

    tree[deco].prototype = this;

    return new tree[deco];

};
tree.RedBalls = function () {

    this.decorate = function () {

        this.RedBalls.prototype.decorate(); // 第7步:先执行原型(这时候是Angel了)的decorate方法

        console.log('Put on some red balls'); // 第8步 再输出 red

        // 将这2步作为RedBalls的decorate方法

    }

};
tree.BlueBalls = function () {

    this.decorate = function () {

        this.BlueBalls.prototype.decorate(); // 第1步:先执行原型的decorate方法,也就是tree.decorate()

        console.log('Add blue balls'); // 第2步 再输出blue

        // 将这2步作为BlueBalls的decorate方法

    }

};
tree.Angel = function () {

    this.decorate = function () {

        this.Angel.prototype.decorate(); // 第4步:先执行原型(这时候是BlueBalls了)的decorate方法

        console.log('An angel on the top'); // 第5步 再输出angel

        // 将这2步作为Angel的decorate方法

    }

};
tree = tree.getDecorator('BlueBalls'); // 第3步:将BlueBalls对象赋给tree,这时候父原型里的getDecorator依然可用

tree = tree.getDecorator('Angel'); // 第6步:将Angel对象赋给tree,这时候父原型的父原型里的getDecorator依然可用

tree = tree.getDecorator('RedBalls'); // 第9步:将RedBalls对象赋给tree
tree.decorate(); // 第10步:执行RedBalls对象的decorate方法

总结

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

Javascript 相关文章推荐
jquery的$getjson调用并获取远程的JSON字符串问题
Dec 10 Javascript
javascript中的undefined和not defined区别示例介绍
Feb 26 Javascript
JavaScript-RegExp对象只能使用一次问题解决方法
Jun 23 Javascript
Javascript常用字符串判断函数代码分享
Dec 08 Javascript
javascript实现行拖动的方法
May 27 Javascript
JQuery中DOM实现事件移除的方法
Jun 13 Javascript
对JavaScript的全文搜索实现相关度评分的功能的方法
Jun 24 Javascript
轻量级javascript 框架Backbone使用指南
Jul 24 Javascript
vue.js的提示组件
Mar 02 Javascript
js es6系列教程 - 新的类语法实战选项卡(详解)
Sep 02 Javascript
es6中比较有用的7个技巧小结
Jul 12 Javascript
实例分析JS中的相等性判断===、 ==和Object.is()
Nov 17 Javascript
jQuery对象与DOM对象之间的相互转换
Mar 03 #Javascript
深入理解JavaScript系列(28):设计模式之工厂模式详解
Mar 03 #Javascript
JS运动基础框架实例分析
Mar 03 #Javascript
jQuery DOM插入节点操作指南
Mar 03 #Javascript
JS运动框架之分享侧边栏动画实例
Mar 03 #Javascript
jQuery DOM删除节点操作指南
Mar 03 #Javascript
JS实现表格数据各种搜索功能的方法
Mar 03 #Javascript
You might like
自己动手做一个SQL解释器
2006/10/09 PHP
一个PHP并发访问实例代码
2012/09/06 PHP
深入apache配置文件httpd.conf的部分参数说明
2013/06/28 PHP
PHP代码实现爬虫记录――超管用
2015/07/31 PHP
thinkphp 抓取网站的内容并且保存到本地的实例详解
2017/08/25 PHP
php+ajax实现无刷新文件上传功能(ajaxuploadfile)
2018/02/11 PHP
jQuery插件scroll实现无缝滚动效果
2015/04/27 Javascript
四种参数传递的形式——URL,超链接,js,form表单
2015/07/24 Javascript
jQuery实现的网页左侧在线客服效果代码
2015/10/23 Javascript
jQuery的ajax和遍历数组json实例代码
2016/08/01 Javascript
React应用中使用Bootstrap的方法
2017/08/15 Javascript
Mac 安装 nodejs方法(图文详细步骤)
2017/10/30 NodeJs
浅析vue.js数组的变异方法
2018/06/30 Javascript
Promise.all中对于reject的处理方法
2018/08/01 Javascript
Vue-Router基础学习笔记(小结)
2018/10/15 Javascript
vue使用keep-alive保持滚动条位置的实现方法
2019/04/09 Javascript
vue2 中二级路由高亮问题及配置方法
2019/06/10 Javascript
vue+elementUI组件table实现前端分页功能
2020/11/15 Javascript
vue-router为激活的路由设置样式操作
2020/07/18 Javascript
[02:56]DOTA2英雄基础教程 巨魔战将
2013/12/10 DOTA
[01:08:56]DOTA2-DPC中国联赛 正赛 Magma vs LBZS BO3 第一场 2月7日
2021/03/11 DOTA
python使用正则表达式提取网页URL的方法
2015/05/26 Python
Python实现的文本简单可逆加密算法示例
2017/05/18 Python
在PyCharm下使用 ipython 交互式编程的方法
2019/01/17 Python
python Shapely使用指南详解
2020/02/18 Python
5分钟弄清楚html5的drag and drop(小结)
2019/04/10 HTML / CSS
三星俄罗斯授权在线商店:Samsung俄罗斯
2019/09/28 全球购物
优秀毕业生求职信范文
2014/01/02 职场文书
四年大学生活的自我评价范文
2014/02/07 职场文书
致铅球运动员加油稿
2014/02/13 职场文书
2015年教师新年寄语
2014/12/08 职场文书
2015年个人剖析材料范文
2014/12/29 职场文书
幼儿园中班教师个人工作总结
2015/02/06 职场文书
导游词之河北白洋淀
2020/01/15 职场文书
JavaScript中isPrototypeOf函数
2021/11/07 Javascript
AngularJS实现多级下拉框
2022/03/25 Javascript