深入理解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 统计时间
Mar 09 Javascript
JavaScript 获取事件对象的注意点
Jul 29 Javascript
Three.js源码阅读笔记(基础的核心Core对象)
Dec 27 Javascript
javascript从image转换为base64位编码的String
Jul 29 Javascript
JS加载iFrame出现空白问题的解决办法
May 13 Javascript
javascript jquery对form元素的常见操作详解
Jun 12 Javascript
基于复选框demo(分享)
Sep 27 Javascript
轻松搞定jQuery+JSONP跨域请求的解决方案
Mar 06 jQuery
JavaScript日期工具类DateUtils定义与用法示例
Sep 03 Javascript
JS中min函数实例讲解
Feb 18 Javascript
使用vuex较为优雅的实现一个购物车功能的示例代码
Dec 09 Javascript
基于vue的video播放器的实现示例
Feb 19 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实现四舍五入的方法小结
2015/03/03 PHP
ThinkPHP开发框架函数详解:C方法
2015/08/14 PHP
php源码 fsockopen获取网页内容实例详解
2016/09/24 PHP
PHP与JavaScript针对Cookie的读写、交互操作方法详解
2017/08/07 PHP
PHP面向对象五大原则之里氏替换原则(LSP)详解
2018/04/08 PHP
laravel框架中表单请求类型和CSRF防护实例分析
2019/11/23 PHP
在VS2008中使用jQuery智能感应的方法
2010/12/30 Javascript
JavaScript中的this实例分析
2011/04/28 Javascript
javascript搜索框效果实现方法
2015/05/14 Javascript
jQuery插件简单实现方法
2015/07/18 Javascript
JavaScript设置表单上传时文件个数的方法
2015/08/11 Javascript
JS实现的自动打字效果示例
2017/03/10 Javascript
EasyUI Datebox 日期验证之开始日期小于结束时间
2017/05/19 Javascript
Vue.js 父子组件通信的十种方式
2018/10/30 Javascript
VUEX 数据持久化,刷新后重新获取的例子
2019/11/12 Javascript
vue3为什么要用proxy替代defineProperty
2020/10/19 Javascript
原生js实现贪吃蛇游戏
2020/10/26 Javascript
vue3.0 自适应不同分辨率电脑的操作
2021/02/06 Vue.js
[05:02]2014DOTA2 TI中国区预选赛精彩TOPPLAY第三弹
2014/06/25 DOTA
Python 文件操作技巧(File operation) 实例代码分析
2008/08/11 Python
python自动化报告的输出用例详解
2018/05/30 Python
对TensorFlow的assign赋值用法详解
2018/07/30 Python
python实现打砖块游戏
2020/02/25 Python
使用sklearn对多分类的每个类别进行指标评价操作
2020/06/11 Python
Python实现石头剪刀布游戏
2021/01/20 Python
网易微博Web App用HTML5开发的过程介绍
2012/06/13 HTML / CSS
医学生求职自荐信
2013/10/25 职场文书
微观物理专业自荐信
2014/01/26 职场文书
代办委托书怎样写
2014/04/08 职场文书
2014年安全生产大检查方案
2014/05/13 职场文书
优秀党支部书记事迹材料
2014/05/29 职场文书
交通工程专业推荐信
2014/09/06 职场文书
明确岗位职责
2015/02/14 职场文书
办公室主任个人总结
2015/02/28 职场文书
汉字听写大会观后感
2015/06/12 职场文书
Python内置数据类型中的集合详解
2022/03/18 Python