深入理解JavaScript系列(29):设计模式之装饰者模式详解

 更新时间:2015年03月03日 11:22:30   投稿:junjie  
这篇文章主要介绍了深入理解JavaScript系列(29):设计模式之装饰者模式详解,装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数),需要的朋友可以参考下

介绍

装饰者提供比继承更有弹性的替代方案。 装饰者用用于包装同接口的对象,不仅允许你向方法添加行为,而且还可以将方法设置成原始对象调用(例如装饰者的构造函数)。

装饰者用于通过重载方法的形式添加新功能,该模式可以在被装饰者前面或者后面加上自己的行为以达到特定的目的。

正文

那么装饰者模式有什么好处呢?前面说了,装饰者是一种实现继承的替代方案。当脚本运行时,在子类中增加行为会影响原有类所有的实例,而装饰者却不然。取而代之的是它能给不同对象各自添加新行为。如下代码所示:

复制代码 代码如下:

//需要装饰的类(函数)
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方法

总结

装饰者模式是为已有功能动态地添加更多功能的一种方式,把每个要装饰的功能放在单独的函数里,然后用该函数包装所要装饰的已有函数对象,因此,当需要执行特殊行为的时候,调用代码就可以根据需要有选择地、按顺序地使用装饰功能来包装对象。优点是把类(函数)的核心职责和装饰功能区分开了。

相关文章

  • 基于js里调用函数时,函数名带括号和不带括号的区别

    基于js里调用函数时,函数名带括号和不带括号的区别

    下面小编就为大家带来一篇基于js里调用函数时,函数名带括号和不带括号的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-07-07
  • 小程序分享链接onShareAppMessage的具体用法

    小程序分享链接onShareAppMessage的具体用法

    这篇文章主要介绍了小程序分享链接onShareAppMessage的具体用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • uni-app中Navigator组件的用法详解及传参方式

    uni-app中Navigator组件的用法详解及传参方式

    这篇文章主要给大家介绍了关于uni-app中Navigator组件的用法详解及传参方式的相关资料,在实际应用开发中我们经常要使用到路由跳转,在uniapp官网中提供了navigator内置组件,供我们使用,需要的朋友可以参考下
    2023-09-09
  • uniapp实现下拉刷新与上拉触底加载功能的示例代码

    uniapp实现下拉刷新与上拉触底加载功能的示例代码

    这篇文章主要记录一下uniapp实现下拉刷新与上拉触底加载功能的示例代码,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-04-04
  • 基于layui的下拉列表的数据回显方法

    基于layui的下拉列表的数据回显方法

    今天小编就为大家分享一篇基于layui的下拉列表的数据回显方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2019-09-09
  • 5个书写JavaScript代码的坏习惯,看看你中枪了没?

    5个书写JavaScript代码的坏习惯,看看你中枪了没?

    这篇文章主要介绍了5个书写JavaScript代码的坏习惯,看看你中枪了没?,本文指出了你没有使用命名空间、变量定义的东一个西一个、Javascript的变量范围、Javascript的面向对象、new关键字等问题,需要的朋友可以参考下
    2014-11-11
  • 详解JavaScript中的作用域链与闭包

    详解JavaScript中的作用域链与闭包

    这篇文章主要为大家详细介绍一下JavaScript中的作用域链与闭包的使用,文中的示例代码讲解详细,对我们学习JavaScript有一定的帮助,需要的可以参考一下
    2022-11-11
  • javaScript嗅探执行神器-sniffer.js

    javaScript嗅探执行神器-sniffer.js

    本文主要介绍了javaScript嗅探执行神器-sniffer.js的相关知识。具有很好的参考价值,下面跟着小编一起来看下吧
    2017-02-02
  • 微信小程序实现幸运大转盘功能的示例代码

    微信小程序实现幸运大转盘功能的示例代码

    这篇文章主要介绍了如何在微信小程序中实现幸运大转盘功能,参与用户点击抽奖便可抽取轮盘的奖品,感兴趣的小伙伴可以跟随小编一起动手试一试
    2022-03-03
  • uniapp小视频项目开发之滑动播放视频

    uniapp小视频项目开发之滑动播放视频

    最近在工作中遇到了一个视频播放的需求,所以下面这篇文章主要给大家介绍了关于uniapp小视频项目开发之滑动播放视频的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2022-04-04

最新评论