深入理解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编写的第一人称射击游戏
Feb 25 Javascript
javascript深入理解js闭包
Jul 03 Javascript
js内存泄露的几种情况详细探讨
May 31 Javascript
jquery中子元素和后代元素的区别示例介绍
Apr 02 Javascript
如何用jquery控制表格奇偶行及活动行颜色
Apr 20 Javascript
jQuery短信验证倒计时功能实现方法详解
May 25 Javascript
javascript实现抽奖程序的简单实例
Jun 07 Javascript
下一代Bootstrap的5个特点 超酷炫!
Jun 17 Javascript
浅析JavaScript动画模拟拖拽原理
Dec 09 Javascript
基于Datatables跳转到指定页的简单实例
Nov 09 Javascript
vue 页面加载进度条组件实例
Feb 05 Javascript
解决Vue中mounted钩子函数获取节点高度出错问题
May 18 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正则表达式使用的详细介绍
2013/04/27 PHP
PHP框架Laravel插件Pagination实现自定义分页
2020/04/22 PHP
php 实现一个字符串加密解密的函数实例代码
2016/11/01 PHP
jQuery 第二课 操作包装集元素代码
2010/03/14 Javascript
java必学必会之static关键字
2015/12/03 Javascript
Bootstrap多级导航栏(级联导航)的实现代码
2016/03/08 Javascript
通过javascript进行UTF-8编码的实现方法
2016/06/27 Javascript
JavaScript 监控微信浏览器且自带返回按钮时间
2016/11/27 Javascript
Vue.js组件tree实现无限级树形菜单
2016/12/02 Javascript
浅谈 Vue v-model指令的实现原理
2017/06/08 Javascript
AngularJs实现聊天列表实时刷新功能
2017/06/15 Javascript
jquery多级树形下拉菜单的实例代码
2019/07/09 jQuery
Vue中使用Echarts仪表盘展示实时数据的实现
2020/11/01 Javascript
vue-quill-editor插入图片路径太长问题解决方法
2021/01/08 Vue.js
用Python脚本来删除指定容量以上的文件的教程
2015/05/04 Python
Python的Flask框架的简介和安装方法
2015/11/13 Python
python下解压缩zip文件并删除文件的实例
2018/04/24 Python
python实现简易内存监控
2018/06/21 Python
Python 存储字符串时节省空间的方法
2019/04/23 Python
Django使用redis缓存服务器的实现代码示例
2019/04/28 Python
django一对多模型以及如何在前端实现详解
2019/07/24 Python
Python 硬币兑换问题
2019/07/29 Python
Python常用库大全及简要说明
2020/01/17 Python
Ubuntu18.04安装 PyCharm并使用 Anaconda 管理的Python环境
2020/04/08 Python
基于HTML5实现类似微信手机摇一摇功能(计算摇动次数)
2017/07/24 HTML / CSS
国外平面设计素材网站:The Hungry JPEG
2017/03/28 全球购物
教师评优事迹材料
2014/01/10 职场文书
加拿大探亲邀请信
2014/01/28 职场文书
查摆问题自我剖析材料
2014/08/18 职场文书
班级光棍节联谊会策划书
2014/10/10 职场文书
2015年推广普通话演讲稿
2015/03/20 职场文书
感恩节寄语2015
2015/03/24 职场文书
聚会通知怎么写
2015/04/23 职场文书
如何写好闭幕词
2019/04/02 职场文书
MySQL示例讲解数据库约束以及表的设计
2022/06/16 MySQL
JS高级程序设计之class继承重点详解
2022/07/07 Javascript