深入理解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 相关文章推荐
javascript英文日期(有时间)选择器
May 02 Javascript
读jQuery之十三 添加事件和删除事件的核心方法
Aug 23 Javascript
获取客户端网卡MAC地址和IP地址实现JS代码
Mar 17 Javascript
解析jQuery与其它js(Prototype)库兼容共存
Jul 04 Javascript
javascript刷新父页面的各种方法汇总
Sep 03 Javascript
究竟什么是Node.js?Node.js有什么好处?
May 29 Javascript
JavaScript中实现键值对应的字典与哈希表结构的示例
Jun 12 Javascript
bootstrap IE8 兼容性处理
Mar 22 Javascript
用js实现before和after伪类的样式修改的示例代码
Sep 07 Javascript
elementUI同一页面展示多个Dialog的实现
Nov 19 Javascript
vue+element_ui上传文件,并传递额外参数操作
Dec 05 Vue.js
vue基于Teleport实现Modal组件
May 31 Vue.js
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 程序员应该使用的10个组件
2009/10/31 PHP
PHPMailer 中文使用说明小结
2010/01/22 PHP
PHP初学者最感迷茫的问题小结
2010/03/27 PHP
第七章 php自定义函数实现代码
2011/12/30 PHP
根据中文裁减字符串函数的php代码
2013/12/03 PHP
Laravel使用memcached缓存对文章增删改查进行优化的方法
2016/10/08 PHP
php使用GD2绘制几何图形示例
2017/02/15 PHP
详解PHP中mb_strpos的使用
2018/02/04 PHP
PHP封装XML和JSON格式数据接口操作示例
2019/03/06 PHP
javascript新手语法小结
2008/06/15 Javascript
简单实用的js调试logger组件实现代码
2010/11/20 Javascript
Node.js中require的工作原理浅析
2014/06/24 Javascript
JavaScript中switch判断容易犯错的一个细节
2014/08/27 Javascript
10条建议帮助你创建更好的jQuery插件
2015/05/18 Javascript
JS实现发送短信验证后按钮倒计时功能(防止刷新倒计时失效)
2017/07/07 Javascript
浅谈vue2 单页面如何设置网页title
2017/11/08 Javascript
基于vue的验证码组件的示例代码
2019/01/22 Javascript
一步一步实现Vue的响应式(对象观测)
2019/09/02 Javascript
压缩Vue.js打包后的体积方法总结(Vue.js打包后体积过大问题)
2020/02/03 Javascript
python学习数据结构实例代码
2015/05/11 Python
Python多线程爬虫简单示例
2016/03/04 Python
Python3爬虫之自动查询天气并实现语音播报
2019/02/21 Python
对python中不同模块(函数、类、变量)的调用详解
2019/07/16 Python
Django高并发负载均衡实现原理详解
2020/04/04 Python
Python 实现将numpy中的nan和inf,nan替换成对应的均值
2020/06/08 Python
如何用Python 加密文件
2020/09/10 Python
Python通过len函数返回对象长度
2020/10/22 Python
Python做图像处理及视频音频文件分离和合成功能
2020/11/24 Python
HTML5之HTML元素扩展(上)—新增加的元素及使用概述
2013/01/31 HTML / CSS
移动端解决悬浮层(悬浮header、footer)会遮挡住内容的3种方法
2015/03/27 HTML / CSS
工业设计专业推荐信
2013/10/29 职场文书
周年庆典邀请函范文
2014/01/24 职场文书
优秀毕业自我鉴定
2014/02/15 职场文书
市场营销求职信范文
2014/02/21 职场文书
团购业务员岗位职责
2014/03/15 职场文书
人力资源管理毕业求职信
2014/08/05 职场文书