用代理模式优雅地写代码

124 阅读4分钟
原文链接: mp.weixin.qq.com

Java的代理模式在开发中经常使用,作为设计模式的一种,在很多场景下都有应用。

代理模式通常分为两种· 静态代理· 动态代理关于代理模式,今天先由浅到深说一下静态代理。

没有代理的世界

通常来说,代理模式是用来解耦的,可以把代理模式认为是加入了中介的 Producer/Consumer 模式。在没有代理的情况下,生产者直接和消费者耦合,这会导致一些问题,比如对某一方的逻辑调整会导致大面积的修改代码。

举一个场景,有个网页向用户提供阅读的功能,产品说你们先把阅读功能上线。好了现在我们知道有一个统一的动作 read(),抽象出来做为接口吧。

interface Func {    void read();}

每个用户都来实现下这个接口,

public class User implements Func {    void read(){    ....    }}

现在当用户进入我们的网页的时候,我们就可以实例化一个用户对象,然后调用它的read方法。为了初步解耦,我们用接口来声明,

Func user = new User();user.read();

so far so good…虽然我们的代码中到处充斥着这种样板代码,重复的实例化和调用接口,但是需求算是实现了。然而这样的耦合程度会给自己挖很深的坑,特别是当需求发生变更的时候。比如下面这样…

引入代理

第一版上线后,用户广泛好评,产品说,既然如此,我们不能免费给用户使用啊,不如我们插个广告吧!

好了,现在我们有两个选择· 在项目中每个实例调用read()的地方前面插一句 playAdv()· 修改 User的 read()实现逻辑,在前面加个 playAdv()

第一个明显会加大我们的工作量,实例化的地方少还好,要是项目里有几百处地方直接调用实例的接口,我们估计要跪…第二种虽然相对优雅,可是坑也不小,因为"播放广告"这个行为并不是用户的,我们希望功能尽可能的纯粹。如果考虑到以后还要区分注册用户/付费用户,第二种修改方式带来的问题也很明显。

其实我们还有第三种选择,引入代理。先上代理的代码

public class Proxy implements Func {    private Func mUser;    public Proxy(Func user) {        this.mUser = user;    }    public void read() {        mUser.read();    }}

上面就是一个简单的代理类的代码了,它也实现了Func的功能,重点是它的通过构造方法传入了一个被代理的 User对象。现在我们来看看引入代理有什么好处。

我们的之前调用 User并实例化的地方会变成这样

Proxy proxy = new Proxy(new User());proxy.read();

咋一看,没什么变化,只是从对 User的调用变成对代理的调用。

但只要仔细思考一下就明白,这样一来,我们就不用关心具体对象的行为了,所有的事情都交给了代理。当产品说要加个广告时,我们也不需要往用户类里加新逻辑(因为那不是用户行为),我们只需要修改一下代理类,

public class Proxy implements Func {    private Func mUser;    public Proxy(Func user) {        this.mUser = user;    }    public void read() {        AdvUtil.playAdv(); <- 播放广告        mUser.read();    }}

至于调用 Proxy的地方,啥都不用改。我们用 Proxy,在Producer和Consumer之间加了一层中介,这样一来即使要对Consumer的行为进行干预,也不用到处去修改代码了。

现在因为 Proxy的存在,就算产品再怎么改需求也不怕了。想加个广告?改一下代理就行。想加个会员免广告?改一下代理就行。

总结

代理模式总结起来就是通过一层 Proxy层,把 Producer和Consumer之间隔开,让他们之间尽可能的少耦合。这样当需要操作 Consumer的行为时,只需要修改 Proxy层,而不需要到处去调整 Producer的代码。

但是静态代理的弊端也是很明显的。当接口的实现类变多时,每次的接口调整也需要修改很多代码。可以想象一下,加入现在有 免费用户/包月用户/包年用户等类型的用户,包括 Proxy,他们都实现了 Func接口,此时如果说要给 Func加一个接口,或者给 read()接口加一个参数,需要调整的代码量也是很可怕的。所以相对静态代理,就有了动态代理这种神奇的东西。我们以后再接着分析动态代理的实现和原理。