深入理解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 option删除代码集合
Nov 12 Javascript
JavaScript常用对象的方法和属性小结
Jan 24 Javascript
使用Java实现简单的server/client回显功能的方法介绍
May 03 Javascript
JS延迟加载加快页面打开速度示例代码
Dec 30 Javascript
浅析Node.js:DNS模块的使用
Nov 23 Javascript
JSON 数据格式详解
Sep 13 Javascript
vue2 前端搜索实现示例
Feb 26 Javascript
浅谈vue中.vue文件解析流程
Apr 24 Javascript
vue移动端实现红包雨效果
Jun 23 Javascript
详解promise.then,process.nextTick, setTimeout 以及 setImmediate的执行顺序
Nov 21 Javascript
Vue数据绑定简析小结
May 07 Javascript
vue中data里面的数据相互使用方式
Jun 05 Vue.js
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中养成7个面向对象的好习惯
2010/07/17 PHP
Yii框架调试心得--在页面输出执行sql语句
2014/12/25 PHP
php获取开始与结束日期之间所有日期的方法
2016/11/29 PHP
JS 获取span标签中的值的代码 支持ie与firefox
2009/08/24 Javascript
jquery 可排列的表实现代码
2009/11/13 Javascript
c#和Javascript操作同一json对象的实现代码
2012/01/17 Javascript
JavaScript 高级篇之函数 (四)
2012/04/07 Javascript
AngularJS 模块详解及简单实例
2016/07/28 Javascript
jQuery监听文件上传实现进度条效果的方法
2016/10/16 Javascript
jQ处理xml文件和xml字符串的方法(详解)
2016/11/22 Javascript
深入理解Vue.js源码之事件机制
2017/09/27 Javascript
一次Webpack配置文件的分离实战记录
2018/11/30 Javascript
说说Vue.js中的functional函数化组件的使用
2019/02/12 Javascript
vue生命周期的探索
2019/04/03 Javascript
微信小程序开发技巧汇总
2019/07/15 Javascript
vue - vue.config.js中devServer配置方式
2019/10/30 Javascript
解决微信小程序scroll-view组件无横向滚动的问题
2020/02/04 Javascript
Vue+tracking.js 实现前端人脸检测功能
2020/04/16 Javascript
JavaScript实现放大镜效果代码示例
2020/04/29 Javascript
深入了解Vue.js 混入(mixins)
2020/07/23 Javascript
[01:00:25]NB vs Secret 2018国际邀请赛小组赛BO1 B组加赛 8.19
2018/08/21 DOTA
Python实现根据IP地址和子网掩码算出网段的方法
2015/07/30 Python
Python实现批量检测HTTP服务的状态
2016/10/27 Python
Python实现的简单排列组合算法示例
2018/07/04 Python
python绘制散点图并标记序号的方法
2018/12/11 Python
Python设计模式之装饰模式实例详解
2019/01/21 Python
python自定义时钟类、定时任务类
2021/02/22 Python
python判断无向图环是否存在的示例
2019/11/22 Python
基于Python获取照片的GPS位置信息
2020/01/20 Python
python request 模块详细介绍
2020/11/10 Python
最好的商品表达自己:Cafepress
2019/09/04 全球购物
会计主管岗位职责范文
2013/11/08 职场文书
个人借条范本
2015/05/25 职场文书
高一数学教学反思
2016/02/18 职场文书
2019学子的答谢词范本!
2019/07/05 职场文书
Python基础之数据结构详解
2021/04/28 Python