深入理解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 相关文章推荐
基于jquery的实现简单的表格中增加或删除下一行
Aug 01 Javascript
jquery实现点击页面计算点击次数
Jan 23 Javascript
BootStrap的弹出框(Popover)支持鼠标移到弹出层上弹窗层不隐藏的原因及解决办法
Apr 03 Javascript
jQuery如何获取动态添加的元素
Jun 24 Javascript
用jquery快速解决IE输入框不能输入的问题
Oct 04 Javascript
微信小程序 label 组件详解及简单实例
Jan 10 Javascript
jQuery 实现左右两侧菜单添加、移除功能
Jan 02 jQuery
Vue实现导出excel表格功能
Mar 30 Javascript
Element-UI Table组件上添加列拖拽效果实现方法
Apr 14 Javascript
vue、react等单页面项目部署到服务器的方法及vue和react的区别
Sep 29 Javascript
Mint UI组件库CheckList使用及踩坑总结
Dec 20 Javascript
基于vue-draggable 实现三级拖动排序效果
Jan 10 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网站建设的流程与步骤分享
2015/09/25 PHP
利用PHP生成静态html页面的原理
2016/09/30 PHP
PHP实现模拟http请求的方法分析
2017/12/20 PHP
Laravel jwt 多表(多用户端)验证隔离的实现
2019/12/18 PHP
学习ExtJS(一) 之基础前提
2009/10/07 Javascript
AngularJS实现元素显示和隐藏的几个案例
2015/12/09 Javascript
Bootstrap开关(switch)控件学习笔记分享
2016/05/30 Javascript
JavaScript兼容浏览器FF/IE技巧
2016/08/14 Javascript
JS监控关闭浏览器操作的实例详解
2017/09/12 Javascript
Node.js笔记之process模块解读
2018/05/31 Javascript
6行代码实现微信小程序页面返回顶部效果
2018/12/28 Javascript
vue实现在线预览pdf文件和下载(pdf.js)
2019/11/26 Javascript
js实现单元格拖拽效果
2020/02/10 Javascript
JavaScript实现网页动态生成表格
2020/11/25 Javascript
微信小程序实现modal弹出框遮罩层组件(可带文本框)
2020/12/20 Javascript
[39:19]完美世界DOTA2联赛PWL S2 SZ vs LBZS 第二场 11.26
2020/11/30 DOTA
Python中使用socket发送HTTP请求数据接收不完整问题解决方法
2015/02/04 Python
Python获取服务器信息的最简单实现方法
2015/03/05 Python
解决python2.7 查询mysql时出现中文乱码
2016/10/09 Python
Python3.5基础之函数的定义与使用实例详解【参数、作用域、递归、重载等】
2019/04/26 Python
python 一个figure上显示多个图像的实例
2019/07/08 Python
Python递归及尾递归优化操作实例分析
2020/02/01 Python
Python3操作读写CSV文件使用包过程解析
2020/04/10 Python
python调用摄像头的示例代码
2020/09/28 Python
Python Tkinter实例——模拟掷骰子
2020/10/24 Python
Django Model层F,Q对象和聚合函数原理解析
2020/11/12 Python
Desigual英国官网:在线购买原创服装
2018/03/09 全球购物
中学生爱国演讲稿
2013/12/31 职场文书
市场安全管理制度
2014/01/26 职场文书
优秀员工获奖感言
2014/03/01 职场文书
国贸专业的职业规划书
2014/03/15 职场文书
法人委托书范本
2014/04/04 职场文书
临时工聘用合同协议书
2014/10/29 职场文书
技术员个人工作总结
2015/03/03 职场文书
银行自荐信怎么写
2015/03/05 职场文书
人生感悟经典句子
2019/08/20 职场文书