手把手教你学设计模式-静态代理(简单易懂)

设计模式-静态代理

不要生搬硬套去使用设计模式,这样会适得其反,我们应该去学习这种思想。
大部分人对于设计模式的实际应用没有明确的意识,也许许多设计模式在你开发中已经使用过了,但你却不知道。
事实上,网上很多人举的例子都有些扯,这些人并没有实战经验,只不过在网上找一些八股文看了看。你在网上搜索 “设计模式” 时,会出现很多文章,但是他们举的例子都是一些没有实战根据的,就有点类似于 “鸟会飞” 这样的例子,是个人都知道鸟会飞,举这样的例子很显然于实际开发没有半毛钱关系,但是给人的感觉是 “我懂了,这就是设计模式”,这也就是导致很多人感觉自己学会了设计模式,但是工作中依然写着一堆又一堆的代码,完全不知道何时用什么设计模式可以使自己代码的可读性变高。



前言

这一章要讲的是设计模式中的 静态代理 模式,问题来了什么是代理模式呢?使用它有什么优势?
给大家举一个小小的例子来解释一下什么是设计模式,假设你女朋友叫闪送给你送了一本书,在这个过程中,闪送快递员就可以理解为是你女朋友的代理,你女朋友委托闪送快递员将书送到你手中。
从这个小小的例子中,你就已经对代理有了印象,就是 委托某人去做某件事,还有很多例子,比如快递、运营商、外包公司等等,这些都是代理思想。
那我们为什么要用代理模式呢?
那上面例子来说,如果不用代理模式的话也是可以的,不过就会显得很沉重,你女朋友坐地铁2小时给你送书,你网上购买了东西需要亲自到商家去拿货等等,映射到程序中也是类似的。


使用场景

对于静态代理来说,在实际开发中更多并不像 前言 里所讲的,从一开始就设计好的。工作中,更多的是 使用静态代理去“弥补”开发时的设计不足,这才是静态代理使用最多的地方(至少对于我来说是的)。当然,在你使用熟练之后就可以在开发前预测到未来可能会遇到的问题,提前使用设计模式去合理设计类于类之间的关系。

假设公司提供了一个id生成器的jar包,供整个公司使用,如下:

public interface IDCreator {

    /**
     * 生成一个唯一id
     * @return
     */
    String create();
}

public class StandardIDCreator implements IDCreator {

    @Override
    public String create() {
        return UUID.randomUUID().toString();
    }
}

该jar包中提供了一个接口和一个默认实现,而我们在项目中使用时,直接去调用StandardIDCreator.create()即可获得一个唯一的id,并且我们在项目中一直也是这样使用的。这时,产品蹦出来说,如果用户通过邀请注册的账号,那我们的id规则需要变更一下,在id之前加上 "app_"这样一个前缀,通过其他渠道注册的用户依然使用原来的id规则。
我们之前的注册服务代码如下:

public class APP1Service {

    IDCreator idCreator;

    public APP1Service(){
        idCreator = new StandardIDCreator();
    }


    public void register(){
        String userId = idCreator.create();
    }
}

可以看到,我们 直接使用 idCreator.create(); 去生成的id。

不用设计模式

如果在不使用设计模式的情况下,我们可以采取这样几种方法去完成这个需求,在邀请注册的服务中,直接使用 “app_”.concat(idCreator.create()),直接采取这种方式去完成,很显然这样也是可以的,但是这样会改动源代码,违反了开闭原则,而且,如果后续产品要求将 “app_” 前缀 改为 “spc_”前缀的话,你就又需要去改动业务逻辑了,这样做无疑是增加了危险性,因为每次改动业务代码都有可能导致bug的出现。
那么我们先来看一下不使用设计模式的情况下,代码是什么样子的。

public void register(){
        //do something
        String userId = idCreator.create();
        String newUserId = "app_".concat(userId);
        //do something
    }

可以看到,我们直接在业务代码中去修改了代码,这只是个简单的例子,可能大家无法感受到,如果这个业务中包含了很多的复杂逻辑以及计算逻辑,那么更改之后需要对改方法进行回归测试。
还有一种方式就是,由于IDCreator是jar包中提供的,我们无法对其源代码进行更改,这时我们会想到,新建一个类去实现 IDCreator ,在里面去实现 create()方法,这种想法是好的,当然你也可以这样做,但是会显的很鸡肋,需要完全重写 create()方法,就像下面这样。

public class CustomIDCreator implements IDCreator{
    @Override
    public String create() {
        String id = UUID.randomUUID().toString();
        return "app_".concat(id);
    }
}

我们重写定义了一个 CustomIDCreator 类去实现了 IDCreator接口,将create()方法进行重写,可以看到 CustomIDCreator 和 StandardIDCreator 中存在大量相同代码,完全可以进行复用,我们可以用 CustomIDCreator 去继承 StandardIDCreator ,重写其中的 create()方法,如下:

public class CustomIDCreator extends StandardIDCreator{
    @Override
    public String create() {
        String id = super.create();
        return "app_".concat(id);
    }
}

这里,我们通过继承实现了代码的复用,也可以说是对 StandardIDCreator 进行了增强。到这里,其实已经很好的解决了这个需求。
那这样看来,我们上面的例子中继承在某种意义上好像是对父类的增强,这种就属于强耦合,并且存在继承关系,如果后续又修改其他需求,这时候你就又需要创建一个类再去继承 CustomIDCreator 或者 StandardIDCreator,由于java是单继承的,所以再没有考虑清楚之前,尽量不要使用继承,尽量要使用组合,除非你能保证他们之间有着直接联系,后续大概率不会又变更时可以选择继承。

使用设计模式

public class IDCreatorProxy implements IDCreator{

    private IDCreator idCreator;

    public IDCreatorProxy(IDCreator idCreator){
        this.idCreator = idCreator;
    }
    
    @Override
    public String create() {
        String id = idCreator.create();
        return "app_".concat(id);
    }
}

在这里我们新建了一个代理类并实现了IDCreator,获得了重写 create() 的机会,并且在内部持有一个 类型为 IDCreator 的成员变量,我们重写了create()方法,很显然,我们已经实现了该需求。
这时候可能有人要问,那上面的继承和现在的组合好像都可以实现,并且代码都差不多,为什么推荐使用组合呢?这个后面会出一章专门讲解 “设计原则”。


总结

静态代理模式其实就是 被代理类不方便或者不能够直接修改源代码时,代理类持有被代理类的实例,可以对被代理类进行聚合处理,从而达到增强被代理的目的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

顿悟的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值