装饰器模式与代理模式的区别_JS设计模式(三):装饰器模式、代理模式

Do more 做的更多,比你上级给你安排的任务!

73df66a323c967bc8fa43bfc792a3215.png

前言

在《不止代码》中提到了几个程序员典型的思维误区:

拜大牛为师 」「 业务代码一样很牛逼 」「 上班太忙没时间学习 」

我之前也是这样的想法,忙时抱怨、闲时迷茫。有一次和同事聊天的时候,他说「 我们大多数的迷茫都是没有计划,大多数的抱怨都是无能的辩解 」。所以我们要做的是「 有计划的利用时间碎片去学习 」。

前面聊了工厂模式、单例模式、适配器模式,这次聊装饰器模式和代理模式。

装饰器模式

装饰器有两个明显的特点:
  • 为对象添加新功能

  • 不改变其原有的结构和功能

我们用一个简单的例子来说明:

class Circle {

    draw() {

        console.log("画一个圆");

    }

}

class Decorator {

    constructor(circle) {

        this.circle = circle;

    }

    draw() {

        this.circle.draw();

        this.setRedBorder(circle);

    }

    setRedBorder(circle) {

        console.log("设置红色边框");

    }

}

//测试

let circle = new Circle();

circle.draw();

//画一个圆

let dec = new Decorator();

dec.draw();

//画一个圆

//设置红色边框

989ee594185241c04ff6dffc025a518a.png

阮一峰老师在《ES6标准入门》中的第21章提到的修饰器就是我们要讲的装饰器。ES2017将引入这个功能,目前浏览器还不支持,但是babel已经实现转码,需要我们下载babel-plugin-transform-decorators-legacy进行配置。

function testTable(target) {

    target.isTestTable = true;

}

@testTable

class TestDemo {}

let test = TestDemo.isTestTable;

console.log(test);

//true

修饰器函数第一个参数就是所要修饰的目标,但是如果要传入多个参数,我们需要进一步封装:

function testTable(isTestTable) {

    return (target) => {

        target.isTestTable = isTestTable;

    };

}

@testTable(true)

class TestDemo {}

如果想添加实例属性,可以通过目标类上的prototype对象来操作:

function minxins(...list) {

    return (target) => {

        Object.assgin(target.prototype, ...list);

    };

}

const Foo = {

    foo() {

        console.log("foo");

    },

};

@minxins(Foo)

class TestDemo {}

let obj = new TestDemo();

obj.foo();

//"foo"

实际开发中,React 与 Redux 库结合使用时常常需要写成下面这样。

class MyReactComponent extends React.Component {}

export default connect(    mapStateToProps,    mapDispatchToProps)(MyReactComponent); 有了装饰器,我们就可以改写上面的代码了。相对来说,后一种写法看上去更容易理解。

@connect(mapStateToProps, mapDispatchToProps)

export default class MyReactComponent extends React.Component {}

修饰器不仅可以修饰类,还可以修饰类的属性 。
class Person {

    @readonly

    name() {

        return `${this.first}${this.last}`;

    }

}

function readonly(target, name, descriptor) {

    // descriptor 对象原来的值如下

    //{

    //  value: specifiedFunction,

    //  enumerable : false ,

    //  configurable: true ,

    //  writable : true

    //};

    descriptor.writable = false;

    return descriptor;

}

readonly(Person.prototype, "name", descriptor);

//类似于

Object.defineProperty(Person.prototype, "name", descriptor);

core-decorators  ( github.com/jayphelps/core-decorators)是一个第三方模块,提供了几个常见的修饰器,比如readonly、autobind等等,通过它可以更好地理解修饰器。

代理模式

代理模式也很好理解:

  • 使用者无权访问目标对象

  • 中间加代理,通过代理做授权和控制

我们用一个简单的例子来说明:

class ReadImg {

    constructor(fileName) {

        this.fileName = fileName;

        this.loadFromDisk(); //初始化拿去

    }

    loadFromDisk() {

        console.log("loading......" + this.fileName);

    }

    display() {

        console.log("display......" + this.fileName);

    }

}

class ProxyImg {

    constructor(fileName) {

        this.readImg = new ReadImg(fileName);

    }

    display() {

        this.readImg.display();

    }

}

//测试

let readImg = new ProxyImg("1.jpg");

readImg.display();

//loading......1.jpg

//display......1.jpg

ES6中提供Proxy来实现代理。在现实中,明星和经纪人就是代理模式很好的事例:

//明星

const star = {

    name: "陈XX",

    age: 24,

    phone: "12312312312",

};

//经纪人

const agent = new Proxy(star, {

    get: function (target, key) {

        if (key === "phone") {

            return "经纪人的手机号";

        }

        if (key === "price") {

            return 1200000;

        }

        return target[key];

    },

    set: function (target, key, val) {

        if (key === "customPrice") {

            if (val < 100000) {

                throw new Error("价格太低");

            } else {

                target[key] = val;

                return true;

            }

        }

    }

});

//测试

console.log(agent.name); //陈XX

console.log(agent.age); //24

console.log(agent.phone); //"经纪人的手机号"

console.log(agent.price); //1200000

agent.customPrice = 90000;

console.log("agent.customPrice", agent.customPrice);

代理模式、适配器模式、装饰器模式都很像,都是对原有对象的封装转化等。适配器模式是为了解决不同平台相同功能的问题,而代理模式是解决对受限对象的访问。

适配器模式和代理模式的区别:

简而言之,适配器是输出一个不同(公用)的接口;代理模式是输出一个一模一样的接口。

装饰器模式和代理模式的区别:

装饰器是原有对象的扩展,原有功能直接用;代理模式用的是经过限制后的原有功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值