专栏首页Phoenix的Android之旅用代理模式优雅地写代码

用代理模式优雅地写代码

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()接口加一个参数, 需要调整的代码量也是很可怕的。 所以相对静态代理,就有了动态代理这种神奇的东西。 我们以后再接着分析动态代理的实现和原理。

本文分享自微信公众号 - Android每日一讲(gh_f053f29083b9),作者:Phoenix

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-04-27

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 哈希碰撞是什么,怎么解决

    Hash是一种校验方法, 其中应用最广为人知的就是 HashMap。 当然Hash算法并不完美,有可能两个不同的原始值在经过哈希运算后得到同样的结果, 这样就是...

    PhoenixZheng
  • 动态代理-进阶高级开发必学技能

    关于代理模式的话题有很多, 在开发中经常用到的应该是静态代理模式,能很好的去耦合。 动态代理是代理模式的另外一种实现。

    PhoenixZheng
  • 揭秘-Android刷量有多容易

    做互联网开发的同学可能对流量这个词很熟悉, 在互联网行业中对一个产品的质量有一些关键指标,比如日活DAU,比如次日留存,点击率。 往往评估一个产品的变现能力会通...

    PhoenixZheng
  • 数据工程师必看:分析数据时常见的 7 类统计陷阱

    我们会发生各种极有可能出现的混淆,数据抽取之后“迷恋”于数字,脑子里没有分析的目标,自己的局限影响指标选择......当分析数据的时候我们都很容易犯错。不过,用...

    AI研习社
  • 灵感专题-蓝色系创意网页设计欣赏

    当我们在浏览Facebook、知乎、Twitter等网站时,大家一定发现了这些网站的共同点,就是在页面元素的设计上都以蓝色调为主。为什么在网页设计中,蓝色会这么...

    奔跑的小鹿
  • 首日1.7亿访问量:穗康小程序口罩预约前后端架构及产品设计

    穗康是广州市政府提供的一个战役小程序,于1月30号上线,最开始版本只有三个功能:个人健康上报、疫情线索上报以及医疗物资上报,后续我们快速迭代了包括口罩预约、在线...

    腾小云
  • 小程序云函数实现发送模板消息

    2.微信开发者工具中点击云开发,打开云开发控制台 选择云函数->新建云函数->输入名称(这里使用pay_success)->确定

    薛定喵君
  • 一位10年Java工作经验的架构师聊Java和工作经验

    时光飞逝,我事业中第一个十年已然结束了。在这十年里,让我收获了很多,跟大家分享一下我在 IT 职场方面的一些个人经验,不一定对每个人都实用,请大家仅作参考吧。

    三哥
  • 一位10年Java工作经验的架构师聊Java和工作经验

    三哥
  • 【前端】:属性选择器

    The original Bootstrap markup is heavily convention-based: all buttons require a...

    WEBJ2EE

扫码关注云+社区

领取腾讯云代金券