深入理解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 相关文章推荐
JS完成代码前最好对其做5件事
Apr 07 Javascript
js post提交调用方法
Feb 12 Javascript
jquery选择器使用详解
Apr 08 Javascript
js控制文本框只输入数字和小数点的方法
Mar 10 Javascript
avalon js实现仿微博拖动图片排序
Aug 14 Javascript
JavaScript正则表达式匹配 div  style标签
Mar 15 Javascript
KnockoutJS 3.X API 第四章之click绑定
Oct 10 Javascript
探讨AngularJs中ui.route的简单应用
Nov 16 Javascript
使用Object.defineProperty如何巧妙找到修改某个变量的准确代码位置
Nov 02 Javascript
jQuery使用$.extend(true,object1, object2);实现深拷贝对象的方法分析
Mar 06 jQuery
详解JS预解析原理
Jun 16 Javascript
正则表达式基础与常用验证表达式
Jun 16 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
用PHP编程语言开发动态WAP页面
2006/10/09 PHP
提升PHP执行速度全攻略(上)
2006/10/09 PHP
微博短链接算法php版本实现代码
2012/09/15 PHP
PHP面向对象程序设计之类常量用法实例
2014/08/20 PHP
laravel框架中间件 except 和 only 的用法示例
2019/07/12 PHP
理解Javascript_14_函数形式参数与arguments
2010/10/20 Javascript
javascript针对DOM的应用实例(一)
2012/04/15 Javascript
自定义ExtJS控件之下拉树和下拉表格附源码
2013/10/15 Javascript
教你如何自定义百度分享插件以及bshare分享插件的分享按钮
2014/06/20 Javascript
JavaScript声明变量时为什么要加var关键字
2014/09/29 Javascript
JavaScript不使用prototype和new实现继承机制
2014/12/29 Javascript
JS实现的鼠标跟随代码(卡通手型点击效果)
2015/10/26 Javascript
Javascript 字符串模板的简单实现
2016/02/13 Javascript
js遍历map javaScript遍历map的简单实现
2016/08/26 Javascript
JavaScript中日常收集常见的10种错误(推荐)
2017/01/08 Javascript
详解webpack中的hash、chunkhash、contenthash区别
2018/01/05 Javascript
vue.js获得当前元素的文字信息方法
2018/03/09 Javascript
nodejs简单抓包工具使用详解
2019/08/23 NodeJs
从表单校验看JavaScript策略模式的使用详解
2020/10/17 Javascript
JavaScript实现跟随鼠标移动的盒子
2021/01/28 Javascript
用Python制作在地图上模拟瘟疫扩散的Gif图
2015/03/31 Python
Python md5与sha1加密算法用法分析
2017/07/14 Python
Python简单计算文件MD5值的方法示例
2018/04/11 Python
opencv调整图像亮度对比度的示例代码
2019/09/27 Python
python实现大量图片重命名
2020/03/23 Python
Python warning警告出现的原因及忽略方法
2020/01/31 Python
英国在线玫瑰专家:InterRose
2019/12/01 全球购物
类和结构的区别
2012/08/15 面试题
英语道歉信范文
2014/01/09 职场文书
小学生关于梦想的演讲稿
2014/08/22 职场文书
单方离婚协议书范本(2014版)
2014/09/30 职场文书
合同和协议有什么区别?
2014/10/08 职场文书
教师党员群众路线教育实践活动心得体会
2014/11/04 职场文书
初一语文教学反思
2016/03/03 职场文书
vue-router中hash模式与history模式的区别
2021/06/23 Vue.js
Go语言 详解net的tcp服务
2022/04/14 Golang