深入理解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 相关文章推荐
使Ext的Template可以解析二层的json数据的方法
Dec 22 Javascript
javascript实现仿腾讯游戏选择
May 14 Javascript
JavaScript实现函数返回多个值的方法
Jun 09 Javascript
JavaScript中字符串与Unicode编码互相转换的实现方法
Dec 18 Javascript
原生js实现图片层叠轮播切换效果
Feb 02 Javascript
JS定义类的六种方式详解
May 12 Javascript
JQuery和PHP结合实现动态进度条上传显示
Nov 23 Javascript
jQuery实现复选框的全选和反选
Feb 02 Javascript
jQuery实现的简单动态添加、删除表格功能示例
Sep 21 jQuery
JavaScript canvas实现雪花随机动态飘落
Feb 08 Javascript
vue实现全屏滚动效果(非fullpage.js)
Mar 07 Javascript
利用javaScript处理常用事件详解
Apr 14 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若干单维数组遍历方法的比较
2011/09/20 PHP
php empty()与isset()区别的详细介绍
2013/06/17 PHP
php函数与传递参数实例分析
2014/11/15 PHP
PHP 常用的header头部定义汇总
2015/06/19 PHP
PHP长连接实现与使用方法详解
2018/02/11 PHP
数据结构之利用PHP实现二分搜索树
2020/10/25 PHP
jQuery创建插件的代码分析
2011/04/14 Javascript
纯JavaScript实现HTML5 Canvas六种特效滤镜示例
2013/06/28 Javascript
js如何打印object对象
2015/10/16 Javascript
jQuery实现标签页效果实战(4)
2017/02/08 Javascript
Vue中的$set的使用实例代码
2018/10/08 Javascript
基于Webpack4和React hooks搭建项目的方法
2019/02/05 Javascript
详解如何更好的使用module vuex
2019/03/27 Javascript
layui对工具条进行选择性的显示方法
2019/09/19 Javascript
JS Thunk 函数的含义和用法实例总结
2020/04/08 Javascript
node.js 如何监视文件变化
2020/09/01 Javascript
[40:05]DOTA2上海特级锦标赛A组小组赛#1 EHOME VS MVP.Phx第一局
2016/02/25 DOTA
PyQt5每天必学之切换按钮
2020/08/20 Python
Python神奇的内置函数locals的实例讲解
2019/02/22 Python
Python高级property属性用法实例分析
2019/11/19 Python
解决django框架model中外键不落实到数据库问题
2020/05/20 Python
python爬虫泛滥的解决方法详解
2020/11/25 Python
html5基础标签(html5视频标签 html5新标签用法)
2013/12/30 HTML / CSS
标记环介质访问控制协议
2016/03/27 面试题
医院后勤自我鉴定
2013/10/13 职场文书
高考自主招生自荐信
2013/10/20 职场文书
毕业生大学生活自我总结
2014/01/31 职场文书
出国留学计划书
2014/04/27 职场文书
经管应届生求职信范文
2014/05/18 职场文书
幼儿园六一活动总结
2014/08/27 职场文书
行政执法队伍作风整顿剖析材料
2014/10/11 职场文书
银行资信证明
2015/06/17 职场文书
导游词之太行山青龙峡
2020/01/14 职场文书
golang 实现并发求和
2021/05/08 Golang
详解Python+OpenCV绘制灰度直方图
2022/03/22 Python
Win11 22H2 2022怎么更新? 获得Win1122H22022版本升级技巧
2022/09/23 数码科技