深入理解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的键盘控制事件说明
Apr 15 Javascript
腾讯UED 漂亮的提示信息效果代码
Sep 12 Javascript
JavaScript常用小技巧小结
Dec 29 Javascript
jQuery中DOM树操作之使用反向插入方法实例分析
Jan 23 Javascript
浅谈JSON中stringify 函数、toJosn函数和parse函数
Jan 26 Javascript
JS处理json日期格式化问题
Oct 01 Javascript
React教程之Props验证的具体用法(Props Validation)
Sep 04 Javascript
深入浅析Vue全局组件与局部组件的区别
Jun 15 Javascript
vue 修改 data 数据问题并实时显示的方法
Aug 27 Javascript
webpack4简单入门实例
Sep 06 Javascript
详解vue-property-decorator使用手册
Jul 29 Javascript
vue实现带过渡效果的下拉菜单功能
Feb 19 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小偷的核心程序
2007/04/09 PHP
php中static静态变量的使用方法详解
2010/06/04 PHP
利用php+mysql来做一个功能强大的在线计算器
2010/10/12 PHP
基于xcache的配置与使用详解
2013/06/18 PHP
php获取文件内容最后一行示例
2014/01/09 PHP
XMLHttpRequest处理xml格式的返回数据(示例代码)
2013/11/21 Javascript
Jquery Post处理后不进入回调的原因及解决方法
2014/07/15 Javascript
JQuery实现超链接鼠标提示效果的方法
2015/06/10 Javascript
Nodejs中 npm常用命令详解
2016/07/04 NodeJs
bootstrap table 数据表格行内修改的实现代码
2017/02/13 Javascript
jQuery修改DOM结构_动力节点Java学院整理
2017/07/05 jQuery
vue绑定class与行间样式style详解
2017/08/16 Javascript
jQuery实现checkbox的简单操作
2017/11/18 jQuery
webpack打包js的方法
2018/03/12 Javascript
详解nuxt sass全局变量(公共scss解决方案)
2018/06/27 Javascript
JS使用Date对象实时显示当前系统时间简单示例
2018/08/23 Javascript
JavaScript实现图片的放大缩小及拖拽功能示例
2019/05/14 Javascript
vue项目中常见问题及解决方案(推荐)
2019/10/21 Javascript
微信小程序中限制激励式视频广告位显示次数(实现思路)
2019/12/06 Javascript
Python随机生成手机号、数字的方法详解
2017/07/21 Python
python中实现控制小数点位数的方法
2019/01/24 Python
使用Python函数进行模块化的实现
2019/11/15 Python
python 对一幅灰度图像进行直方图均衡化
2020/10/27 Python
Css3新特性应用之形状总结
2016/12/08 HTML / CSS
HTML5 video循环播放多个视频的方法步骤
2020/08/06 HTML / CSS
Sneaker Studio波兰:购买运动鞋
2018/04/28 全球购物
夏洛特和乔治婴儿和儿童时装精品店:Charlotte and George
2018/06/06 全球购物
网络教育自我鉴定
2013/11/01 职场文书
人力资源管理专业自荐书范文
2014/02/10 职场文书
学生周末回家住宿长期请假条
2014/02/15 职场文书
民族团结先进集体事迹材料
2014/05/22 职场文书
党性锻炼的心得体会
2014/09/03 职场文书
街道党工委党的群众路线教育实践活动对照检查材料思想汇报
2014/10/05 职场文书
招商引资工作汇报
2014/10/28 职场文书
小学教学工作总结2015
2015/05/13 职场文书
2015年财政局工作总结
2015/05/21 职场文书