设计模式系列整理-03-代理模式

结构型模式

前面两章

主要是介绍创建型模式

今天开始介绍结构型

主要分为7种

分别是:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式

他们的共同特点是,通过组合,让简单的类组成更大、更复杂的结构

首先介绍我最喜欢用的:代理模式

代理模式

代理的核心是

对象直接不直接调用

而是有一个代理者作为中介

形式上满足调用的规则

很多人读书时

不敢和喜欢的同学表白

而是让其他同学传话

这个传声筒,就是代理

常见的代理

生活中的代理很多

房产中介、快递小哥、代办年检……

这些共同特点是,某人需要一项服务

但他自己不方便、不会、不擅长

所以需要一个代理来做

还有另一种

比如:传达室大爷、总裁的秘书……

某人需要接触到对方

但对方不让你接触

只能间接进行联系

写一个最简单的代理类

写一个发短信的例子

public class SmsMessageProxy{
    /**
     * 电信的短信服务
     */
    private ChinaTelecomSmsService service;

    /**
     * 服务访问令牌
     */
    private String access_token="JSHDQ-EKQKH-KKAOW-9WWJE"; 

    public void send(String mobile, String content){
        service.send(access_token, new Date(),mobile, content);
    }
}

public class BizController{
    private SmsMessageProxy smsMessageProxy;

    public DTO finish(Param param){
        // ...
        smsMessageProxy.send(param.getMobile(), "您的业务已办结");
        return DTO.success();
    }
}

这就是一个简单的例子

有3个类

  1. BizController
  2. SmsMessageProxy
  3. ChinaTelecomSmsService

1 作为业务的执行者,无法和 3 直接通讯

而是间接使用了 2 这个代理类

通过间接调用,形式上完成了 1~3 的调用

我们可以发现

代理类除了转发请求之外

还额外做了令牌传参,日期传参工作

其实是简化了调用的参数

给他们提供了默认值

这样做对使用方是有利的

代理的应用场景

试想一下

我有没有这方面的需要

比如监控,比如统计,还有事务、日志、权限等等

这些其实都可以用代理proxy来实现

主要解决一些非功能性的需求开发

以日志为例

核心功能类只需瞒住功能性的需求

然后用代理进行包装

将日志写在代理类中

这样的话,直接调用核心类是没有日志的

当需要日志时,采用代理转发的方式实现。

静态代理

上面的示范是最简单的代理

一个目标类 target

一个代理类 proxy

他们彼此对应

因此有人经常将两者共同抽象出一套接口

这种代理方式可以解决常规的一些问题

比如:

/**
 * 短信服务接口
 */
public interface SmsService{
    void send(String mobile, String content);
}


/**
 * 电信短信服务
 */
public class TelecomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送电信短信
    }
}


/**
 * 代理类
 */
public class SmsProxy implements SmsService{
    private SmsService service;
    public void send(String mobile, String content){
        // TODO 设置请求 header 等鉴权信息
        service.send(mobile, content);
        // TODO 记录发送日志
    }
}

/**
 * 测试类
 */
public class ProxyTest{
    @Test
    void test(){
        SmsProxy proxy=new SmsProxy();
        proxy.send("13812345678", "我爱你");
    }
}

这就是简单的实现

在Spring的AOP里

就大量的使用了代理模式

大家如果经常看日志

就会对proxy这个词不陌生

静态代理存在的问题

前面这个例子能解决简单问题

但随着类的内容越来越多

每次 target 类发生变化,或者增加子类

proxy 都有可能需要同步调整

这加大了维护的代价

因此我们希望有一种尽量少改代码的方法

动态代理

动态代理的核心是反射 reflect

他能解决,一个类,对另外一堆相似的类的统一代理问题

还是前面的例子,我们有一个电信短信类

但后面可能会扩充 移动 和 联通

如果想少改代码

应该怎么做呢?

来看一个示范

/**
 * 短信服务接口
 */
public interface SmsService{
    void send(String mobile, String content);
}


/**
 * 电信短信服务
 */
public class TelecomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送电信短信
    }
}

// 以上两个类和前面一样,下面是新增的类


/**
 * 联通短信服务
 */
public class UnicomSmsService implements SmsService{
    public void send(String mobile, String content){
        // TODO 发送联通短信
    }
}

/**
 * 微信服务,接口和前面的不一样,但方法名类似
 */
public class WechatService implements NetService{
    public void send(String appid, String openid, String content){
        // TODO 发送微信公众号消息
    }
}

现在问题变复杂了

不但有多个平行子类

还有个完全搭不上关系的微信消息类

此时代理怎么做呢?


Java里有一个代理公共接口 InvocationHandler

他的用法我们举一个例子


public class MessageProxy implements InvocationHandler {
    private Object bean;

    public MessageProxy(Object bean) {
        this.bean=bean;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object re=null;
        String methodname=method.getName();
        if (methodname.equals("send")){
            // TODO 设置请求 header 等鉴权信息
            re = method.invoke(bean, args);
            // TODO 记录发送日志
        }
        return re;
    }
}

/**
 * 测试类
 */
public class ProxyTest{
    @Test
    void test(){
		MessageProxy proxy=new MessageProxy(new TelecomSmsService());
		SmsService service0=(SmsService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
		service0.send("13812345678", "我爱你");

		MessageProxy proxy1=new MessageProxy(new UnicomSmsService());
		SmsService service1=(SmsService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
		service0.send("13812345678", "我爱你");

		MessageProxy proxy2=new MessageProxy(new WechatService());
		NetService service2=(NetService)Proxy.newProxyInstance(proxy.getClass().getClassLoader(), new Class[] {SmsService.class}, proxy);
		service0.send("wx81283123", "oejak8123123", "我爱你");
    }
}

可以发现

动态代理类能够适用变化的问题

当目标类发生变化

代理类可以不变

甚至可以一个代理管多个目标类

这就是通过反射来实现的

总结

代理模式是一种常用的设计模式

解决类之间的线性调用问题

通过代理

可以使非功能需求得到很好的解决

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
当代码中的条件语句if-else过于复杂时,可以考虑使用设计模式代替if-else语句,提高代码的可读性和可维护性。以下是一些常见的设计模式,可以用来代替if-else语句: 1. 工厂模式(Factory Pattern):通过工厂方法创建对象,而不是使用条件语句来直接创建对象。这样可以避免在代码中使用大量的if-else语句,同时也可以很方便地添加新的对象类型。 2. 状态模式(State Pattern):将复杂的状态判断逻辑封装到不同的状态类中,避免在代码中使用大量的if-else语句。可以很方便地添加新的状态类型,也可以方便地维护和扩展状态的行为。 3. 策略模式(Strategy Pattern):将不同的算法封装到不同的策略类中,通过选择不同的策略类来实现不同的行为。这样可以避免在代码中使用复杂的if-else语句,同时也可以很方便地添加新的算法类型。 4. 观察者模式(Observer Pattern):将一个对象的状态变化通知给多个观察者对象,避免在代码中使用大量的if-else语句。可以很方便地添加新的观察者对象,也可以方便地维护和扩展观察者的行为。 5. 责任链模式(Chain of Responsibility Pattern):将多个处理对象组成一个链,每个处理对象都可以处理请求,如果一个对象不能处理请求,则将请求传递给下一个处理对象。这样可以避免在代码中使用大量的if-else语句,同时也可以很方便地添加新的处理对象。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

全粘架构师

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

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

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

打赏作者

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

抵扣说明:

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

余额充值