设计模式|JavaScript实现代理模式(上篇)

·  阅读 256

这是我参与更文挑战的第25天,活动详情查看:更文挑战

文章引导

代理模式篇幅较多,分为上、中、下三篇进行整理。

JavaScript实现代理模式(上篇)

内容梗概:主要介绍什么是代理模式,代理模式的简单实现

链接:juejin.cn/post/697850…

JavaScript实现代理模式(中篇)

内容梗概:分析代理模式的各种用途

链接:juejin.cn/post/697903…

JavaScript实现代理模式(下篇)

内容梗概:基于ES6 Proxy API实现更方便的代理模式

链接:juejin.cn/post/697924…

什么是代理模式

代理模式是一种结构化设计模式(小灰的文章认为也可以算作是行为型设计模式),代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用,这就是代理模式的定义。通俗的讲,代理模式的核心是在被调用方和调用方之间增加一个中介者的角色,也就是代理。

proxy-1.png

图源自小灰的文章"什么是代理模式?"

现实生活中,比如我们有租房需求,可能就需要经过房屋中介,让我们认识能够找到合适的房东。

在求职高薪岗位的时候,我们也需要找到猎头,给我们推荐合适的公司。

代理模式在现实生活中无处不在……

当然,你觉得代理模式可能会让简单的事情变复杂,但中介者的角色实际上会给你减少很多麻烦和成本,在代码中代理模式可以避免对业务类的侵入,把日志、事务之类和业务无关的辅助功能单独拎出来。

代理模式有以下两个优点:

中介隔离作用:

在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

符合代码设计的开放-封闭原则:

代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开放-封闭原则

代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。

真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

代理模式虽然和装饰者模式很相似,但是装饰器模式会对装饰对象增加功能,而代理模式并不会对源对象有改变,从外层去操作了这个对象,对象本身是不会有其他的改变。

代理模式的缺点主要是增加了系统的复杂度,要斟酌当前场景是不是真的需要引入代理模式。

实现代理模式

这里用《JavaScript设计模式与开发实践》一书中的例子。

小明想要追一个小姐姐,想给小姐姐送一束花表白。在不使用代理模式和使用代理模式的简单例子。

不使用代理模式

ES5

// 鲜花类
var Flower = function(){};
// 小明
var xiaoming = {
    sendFlower: function( target ){
        var flower = new Flower();
        target.receiveFlower( flower );
    }
};
// 小姐姐
var cuteGirl = {
    receiveFlower: function( flower ){
        console.log( '收到花 ' + flower );
    }
};
// 小明将鲜花直接交给小姐姐
xiaoming.sendFlower( cuteGirl );
复制代码

ES6

// 鲜花类
class Flower {
    
}
// 小明
let xiaoming = {
    sendFlower(target){
        let flower = new Flower();
        target.receiveFlower( flower );
    }
}
// 小姐姐
let cuteGirl = {
    receiveFlower(flower){
        console.log( '收到花 ' + flower );
    }
}
// 小明将鲜花直接交给小姐姐
xiaoming.sendFlower( cuteGirl );
复制代码

使用代理模式

以上就是不使用代理模式的例子,小明在不了解小姐姐喜好的情况下,贸然直接表白被拒绝的概率非常大,但是小明的好朋友恰好认识小姐姐的舍友,舍友会在小姐姐心情好的时候,帮小明把鲜花转交给小姐姐。

ES5

// 鲜花类
var Flower = function(){};
// 小明
var xiaoming = {
    sendFlower: function( target){
        var flower = new Flower();
        target.receiveFlower( flower );
    }
};
// 好朋友
var goodFriend = {
    receiveFlower: function( flower ){
        cuteGirl.listenGoodMood(function(){    // 监听A的好心情
            cuteGirl.receiveFlower( flower );
        });
    }
};
// 小姐姐
var cuteGirl = {
    receiveFlower: function( flower ){
        console.log( '收到花 ' + flower );
    },
    listenGoodMood: function( fn ){
        setTimeout(function(){    // 假设10秒之后A的心情变好
            fn();
        }, 10000 );
    }
};
// 小明将鲜花交给好朋友,委托好朋友在小姐姐心情好的时候将鲜花转交给小姐姐
xiaoming.sendFlower( goodFriend );
复制代码

ES6

// 鲜花类
class Flower {
    
}
// 小明
let xiaoming = {
    sendFlower(target){
        let flower = new Flower();
        target.receiveFlower( flower );
    }
};
// 好朋友
let goodFriend = {
    receiveFlower(flower){
        cuteGirl.listenGoodMood(() => {    // 监听A的好心情
            cuteGirl.receiveFlower( flower );
        });
    }
};
// 小姐姐
let cuteGirl = {
    receiveFlower( flower ){
        console.log( '收到花 ' + flower );
    },
    listenGoodMood( fn ){
        setTimeout(() => {    // 假设10秒之后A的心情变好
            fn();
        }, 10000 );
    }
};
// 小明将鲜花交给好朋友,委托好朋友在小姐姐心情好的时候将鲜花转交给小姐姐
xiaoming.sendFlower( goodFriend );
复制代码

参考资料

[CUG-GZ]前端知识进阶——代理模式

www.yuque.com/cuggz/feplu…

前端设计模式之代理模式

juejin.cn/post/684490…

漫画:什么是 “代理模式” ?

mp.weixin.qq.com/s/O8_A2Ms9M…

JavaScript设计模式与开发实践

www.ituring.com.cn/book/1632

从ES6重新认识JavaScript设计模式(五): 代理模式和Proxy

segmentfault.com/a/119000001…

使用 JavaScript 原生的 Proxy 优化应用

juejin.cn/post/684490…

分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改