深入理解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 动态将数字金额转化为中文大写金额
May 14 Javascript
js实现的仿新浪微博完美的时间组件升级版
Dec 20 Javascript
JS中怎样判断undefined(比较不错的方法)
Mar 27 Javascript
JavaScript闭包函数访问外部变量的方法
Aug 27 Javascript
jQuery获得指定元素坐标的方法
Apr 14 Javascript
jQuery中 prop() attr()使用详解
May 19 Javascript
jQuery+css实现的时钟效果(兼容各浏览器)
Jan 27 Javascript
JS & JQuery 动态添加 select option
Jun 08 Javascript
JQuery学习总结【一】
Dec 01 Javascript
jquery获取select,option所有的value和text的实例
Mar 06 Javascript
微信小程序中显示html格式内容的方法
Apr 25 Javascript
vue+eslint+vscode配置教程
Aug 09 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 中文处理函数集合
2008/08/27 PHP
常见的PHP五种设计模式小结
2011/03/23 PHP
php缩放图片(根据宽高的等比例缩放)实例介绍
2013/06/09 PHP
php生成缩略图示例代码分享(使用gd库实现)
2014/01/20 PHP
PHP对接微信公众平台消息接口开发流程教程
2014/03/25 PHP
php set_include_path函数设置 include_path 配置选项
2016/10/30 PHP
对 lightbox JS 图片控件进行了一下改造, 使其他支持复杂的图片说明
2010/03/20 Javascript
JSON JQUERY模板实现说明
2010/07/03 Javascript
简单的前端js+ajax 购物车框架(入门篇)
2011/10/29 Javascript
js实现无需数据库的县级以上联动行政区域下拉控件
2013/08/14 Javascript
IE浏览器中图片onload事件无效的解决方法
2014/04/29 Javascript
jQuery表格插件datatables用法总结
2014/09/05 Javascript
使用getBoundingClientRect方法实现简洁的sticky组件的方法
2016/03/22 Javascript
文件上传,iframe跨域数据提交的实现
2016/11/18 Javascript
jQuery动态产生select option下拉列表
2017/03/15 Javascript
vue刷新和tab切换实例
2018/02/11 Javascript
vue用Object.defineProperty手写一个简单的双向绑定的示例
2018/07/09 Javascript
JavaScript运动原理基础知识详解
2020/04/02 Javascript
解决Mint-ui 框架Popup和Datetime Picker组件滚动穿透的问题
2020/11/04 Javascript
python DataFrame获取行数、列数、索引及第几行第几列的值方法
2018/04/08 Python
python-OpenCV 实现将数组转换成灰度图和彩图
2020/01/09 Python
在TensorFlow中实现矩阵维度扩展
2020/05/22 Python
如何清空python的变量
2020/07/05 Python
去除python中的字符串空格的简单方法
2020/12/22 Python
CSS3制作文字半透明倒影效果的两种实现方式
2014/08/08 HTML / CSS
HTML5等待加载动画效果
2017/07/27 HTML / CSS
使用HTML5的Canvas绘制曲线的简单方法
2015/09/08 HTML / CSS
德国奢侈品网上商城:Mytheresa
2016/08/24 全球购物
美国球鞋寄卖网站:Stadium Goods
2018/05/09 全球购物
通信研究生自荐信
2014/02/01 职场文书
有多年工作经验的自我评价
2014/03/02 职场文书
英语邀请函范文
2015/02/02 职场文书
2015年政务公开工作总结
2015/05/19 职场文书
音乐课《小猫钓鱼》教学反思
2016/02/18 职场文书
Python爬取英雄联盟MSI直播间弹幕并生成词云图
2021/06/01 Python
Mysql数据库中datetime、bigint、timestamp来表示时间选择,谁来存储时间效率最高
2021/08/23 MySQL