深入理解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 GridView 实现自动计算操作代码
Mar 25 Javascript
javascript模拟实现C# String.format函数功能代码
Nov 25 Javascript
禁用Enter键表单自动提交实现代码
May 22 Javascript
node.js中的fs.chownSync方法使用说明
Dec 16 Javascript
Bootstrap每天必学之下拉菜单
Nov 25 Javascript
使用JS中的exec()方法构造正则表达式验证
Aug 01 Javascript
超详细的JS弹出窗口代码大全
Apr 18 Javascript
JS简单封装的图片无缝滚动效果示例【测试可用】
Mar 22 Javascript
原生JS实现N级菜单的代码
May 21 Javascript
Vue使用zTree插件封装树组件操作示例
Apr 25 Javascript
Vue+Express实现登录注销功能的实例代码
May 05 Javascript
vue+swiper实现左右滑动的测试题功能
Oct 30 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日期时间函数的高级应用技巧
2009/05/16 PHP
PHP生成二维码的两个方法和实例
2014/07/01 PHP
判断、添加和删除WordPress置顶文章的相关PHP函数小结
2015/12/10 PHP
ThinkPHP实现分页功能
2017/04/28 PHP
不安全的常用的js写法
2009/09/15 Javascript
jquery1.4后 jqDrag 拖动 不可用
2010/02/06 Javascript
jQuery阻止同类型事件小结
2013/04/19 Javascript
jQuery实现复选框全选/取消全选/反选及获得选择的值
2014/06/12 Javascript
原生javascript实现简单的datagrid数据表格
2015/01/02 Javascript
js实现使用鼠标拖拽切换图片的方法
2015/05/04 Javascript
javascript去除空格方法小结
2015/05/21 Javascript
判断访客终端类型集锦
2015/06/05 Javascript
基于jQuery实现鼠标点击导航菜单水波动画效果附源码下载
2016/01/06 Javascript
Jquery组件easyUi实现选项卡切换示例
2016/08/23 Javascript
浅析Node.js:DNS模块的使用
2016/11/23 Javascript
jQuery中的on与bind绑定事件区别实例详解
2017/02/28 Javascript
微信小程序实现给循环列表添加点击样式实例
2017/04/26 Javascript
微信小程序实现动态设置placeholder提示文字及按钮选中/取消状态的方法
2017/12/14 Javascript
解决vue多个路由共用一个页面的问题
2018/03/12 Javascript
JS构造一个html文本内容成文件流形式发送到后台
2018/07/31 Javascript
[05:07]DOTA2英雄梦之声_第14期_暗影恶魔
2014/06/20 DOTA
[04:49]期待西雅图之战 2016国际邀请赛中国区预选赛WINGS战队赛后采访
2016/06/29 DOTA
[02:10]探秘浦东源深体育馆 DOTA2 Supermajor不见不散
2018/05/17 DOTA
Python 爬虫的工具列表大全
2016/01/31 Python
python中json格式数据输出的简单实现方法
2016/10/31 Python
Python深入06——python的内存管理详解
2016/12/07 Python
python中 logging的使用详解
2017/10/25 Python
Django中cookie的基本使用方法示例
2018/02/03 Python
django Serializer序列化使用方法详解
2018/10/16 Python
python 实现返回一个列表中出现次数最多的元素方法
2019/06/11 Python
django中账号密码验证登陆功能的实现方法
2019/07/15 Python
Python collections中的双向队列deque简单介绍详解
2019/11/04 Python
父母寄语大全
2014/04/12 职场文书
呐喊读书笔记
2015/06/30 职场文书
培训学校2015年度工作总结
2015/07/20 职场文书
2016年教师党员承诺书范文
2016/03/24 职场文书