深入理解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自定义事件代码说明
Jan 31 Javascript
Jquery 数据选择插件Pickerbox使用介绍
Aug 24 Javascript
原生javascript实现DIV拖拽并计算重复面积
Jan 02 Javascript
用JavaScript动态建立或增加CSS样式表的实现方法
May 20 Javascript
Bootstrap页面布局基础知识全面解析
Jun 13 Javascript
Bootstrap Table服务器分页与在线编辑应用总结
Aug 08 Javascript
基于JavaScript实现的快速排序算法分析
Apr 14 Javascript
Javascript中的async awai的用法
May 17 Javascript
jQuery实现每日秒杀商品倒计时功能
Sep 06 jQuery
VUE+elementui面包屑实现动态路由详解
Nov 04 Javascript
JavaScript实现简单贪吃蛇效果
Mar 09 Javascript
Jquery高级应用Deferred对象原理及使用实例
May 28 jQuery
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 preg_filter执行一个正则表达式搜索和替换
2012/02/27 PHP
谈谈关于php的优点与缺点
2013/04/11 PHP
Laravel 5.0 发布 新版本特性详解
2015/02/10 PHP
Laravel中使用FormRequest进行表单验证方法及问题汇总
2016/06/19 PHP
PHP微信开发之有道翻译
2016/06/23 PHP
JavaScript 参考教程
2006/12/29 Javascript
JavaScript中继承的一些示例方法与属性参考
2010/08/07 Javascript
DIV+CSS+JS不间断横向滚动实现代码
2013/03/19 Javascript
SOSO地图JS画出标注和中心点以html形式运行
2013/08/09 Javascript
js Object2String方便查看js对象内容
2014/11/24 Javascript
浅析jQuery EasyUI中的tree使用指南
2014/12/18 Javascript
JavaScript焦点事件、鼠标事件和滚轮事件使用详解
2016/01/15 Javascript
javascript 数组的定义和数组的长度
2016/06/07 Javascript
小程序实现简单语音聊天的示例代码
2020/07/24 Javascript
python版微信跳一跳游戏辅助
2018/01/11 Python
python删除文本中行数标签的方法
2018/05/31 Python
python 实现敏感词过滤的方法
2019/01/21 Python
Python常见读写文件操作实例总结【文本、json、csv、pdf等】
2019/04/15 Python
python实现支付宝转账接口
2019/05/07 Python
Tensorflow获取张量Tensor的具体维数实例
2020/01/19 Python
深入浅析Python 命令行模块 Click
2020/03/11 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
2020/03/18 Python
python 图像判断,清晰度(明暗),彩色与黑白实例
2020/06/04 Python
python用Configobj模块读取配置文件
2020/09/26 Python
Python远程linux执行命令实现
2020/11/11 Python
高级运动鞋:GREATS
2019/07/19 全球购物
int和Integer有什么区别
2013/05/25 面试题
骨干教师培训感言
2014/01/16 职场文书
民族团结先进个人材料
2014/02/05 职场文书
人事专员工作职责
2014/02/22 职场文书
银行奉献演讲稿
2014/09/16 职场文书
分居协议书范本
2014/11/03 职场文书
初中开学典礼新闻稿
2015/07/17 职场文书
会议承办单位欢迎词
2015/09/30 职场文书
Python并发编程实例教程之线程的玩法
2021/06/20 Python
介绍一下28个JS常用数组方法
2022/05/06 Javascript