深入理解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入门学习书籍推荐
Jun 12 Javascript
解析Jquery中如何把一段html代码动态写入到DIV中(实例说明)
Jul 09 Javascript
快速查找数组中的某个元素并返回下标示例
Sep 03 Javascript
javascript 小数取整简单实现方式
May 30 Javascript
js中通过父级进行查找定位元素
Jun 15 Javascript
jquery中使用循环下拉菜单示例代码
Sep 24 Javascript
JS实现刷新父页面不弹出提示框的方法
Jun 22 Javascript
NODE.JS跨域问题的完美解决方案
Oct 20 Javascript
JS实现间歇滚动的运动效果实例
Dec 22 Javascript
vue判断input输入内容全是空格的方法
Mar 02 Javascript
vue权限路由实现的方法示例总结
Jul 29 Javascript
JavaScript JSON使用原理及注意事项
Jul 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&&mysql)三
2006/10/09 PHP
关于Sphinx创建全文检索的索引介绍
2013/06/25 PHP
wampserver改变默认网站目录的办法
2015/08/05 PHP
PHP树形结构tree类用法示例
2019/02/01 PHP
传智播客学习之java 反射
2009/11/22 Javascript
使用Firebug对js进行断点调试的图文方法
2011/04/02 Javascript
jQuery表格排序组件-tablesorter使用示例
2014/05/26 Javascript
jQuery动态创建html元素的常用方法汇总
2014/09/05 Javascript
jquery+javascript编写国籍控件
2015/02/12 Javascript
学习JavaScript设计模式之享元模式
2016/01/18 Javascript
js判断输入字符串是否为空、空格、null的方法总结
2016/06/14 Javascript
JS实用的带停顿的逐行文本循环滚动效果实例
2016/11/23 Javascript
jQuery实现两列等高并自适应高度
2016/12/22 Javascript
激动人心的 Angular HttpClient的源码解析
2017/07/10 Javascript
JS开发中基本数据类型具体有哪几种
2017/10/19 Javascript
详解如何用模块化的方式写vuejs
2017/12/16 Javascript
浅谈基于Vue.js的移动组件库cube-ui
2017/12/20 Javascript
vue-cli2.0转3.0之项目搭建的详细步骤
2018/12/11 Javascript
详解微信小程序工程化探索之webpack实战
2020/04/20 Javascript
通过vue刷新左侧菜单栏操作
2020/08/06 Javascript
uniapp微信小程序实现一个页面多个倒计时
2020/11/01 Javascript
Python ORM框架SQLAlchemy学习笔记之映射类使用实例和Session会话介绍
2014/06/10 Python
python利用beautifulSoup实现爬虫
2014/09/29 Python
Python读取xlsx文件的实现方法
2019/07/04 Python
python实现的分析并统计nginx日志数据功能示例
2019/12/21 Python
交通事故协议书
2014/04/15 职场文书
优秀少先队员主要事迹材料
2014/05/28 职场文书
喝酒驾驶检讨书
2014/10/01 职场文书
委托公证书样本
2015/01/23 职场文书
婚礼伴郎致辞
2015/07/28 职场文书
红领巾广播站广播稿
2015/08/19 职场文书
2019广播稿怎么写
2019/04/17 职场文书
社交电商模式的兴起:这些新的商机千万别错过
2019/07/26 职场文书
CSS3 制作的图片滚动效果
2021/04/14 HTML / CSS
openGauss数据库JDBC环境连接配置的详细过程(Eclipse)
2022/06/01 Java/Android
js基于div丝滑实现贝塞尔曲线
2022/09/23 Javascript