代理模式

目录

现实例子

概念

使用场景

作用和意义

1、中介隔离作用

2、开闭原则,增加功能

优缺点

优点

缺点

UML结构图

角色构成

抽象主题(Subject)类

真实主题(Real Subject)类

代理(Proxy)类

代理模式的种类

静态代理

定义

优点

缺点

动态代理

定义

小结

静态代理和动态代理区别和联系

共同点

不同点

代码实现

静态代理

ILogger.java

RealLog.java

LogProxy.java

StaticProxyClient.java

静态代理控制台输出

动态代理

LogUtils.java(只是工具类)

ICalculator.java

MyCalculatorImpl.java

CalculatorProxy.java

DynamicProxyClient.java

动态代理控制台输出

​ 


现实例子

什么是代理模式?举个例子来说明:假如说我现在想买一辆二手车,虽然我可以自己去找车源,做质量检测等一系列的车辆过户流程,但是这确实太浪费我得时间和精力了。我只是想买一辆车而已为什么我还要额外做这么多事呢?于是我就通过中介公司来买车车,他们来给我找车源,帮我办理车辆过户流程,我只是负责选择自己喜欢的车,然后付钱就可以了。

再比如打官司, 为什么要找个律师? 因为你不想参与中间过程的是是非非, 只要完成自己的答辩就成, 其他的事前调查、事后追查等都由律师来搞定, 这就是为了减轻你的负担。

概念

为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用。

使用场景

1、限制目标对象。

2、保护目标对象。

3、增强目标对象。

作用和意义

1、中介隔离作用

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

2、开闭原则,增加功能

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

代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

优缺点

优点

1、代理模式能将代理对象与真实对象被调用的目标对象分离。

2、一定程度上降低了系统的耦合度,扩展性好。

3、保护目标对象。

4、增强目标对象。

缺点

1、代理模式会造成系统设计中类的数目的增加。

2、在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

3、增加了系统的复杂度。

UML结构图

角色构成

抽象主题(Subject)类

通过接口或抽象类声明真实主题和代理对象实现的业务方法。

真实主题(Real Subject)类

实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。

代理(Proxy)类

提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

代理模式的种类

按照代理创建的时期来进行分类的话:可以分为两种:静态代理、动态代理。

静态代理

定义

代理类在编译期就生成。

优点

可以做到在符合开闭原则的情况下对目标对象进行功能扩展。

缺点

我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。

动态代理

定义

代理类在程序运行时,运用反射机制动态创建而成。

小结

虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业务接口的依赖,降低了耦合度。但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏。

静态代理和动态代理区别和联系

共同点

两种代理模式实现都在不改动基础对象的前提下,对基础对象进行访问控制和扩展,符合开闭原则。

不同点

静态代理在程序规模稍大时,重复性和脆弱性的缺点凸显;动态代理(搭配泛型参数)实现了一个代理同时处理N多个基础接口,本质上是代理类和基础接口的解耦,一定程度上规避了静态代理的缺点。

 从原理上讲,静态代理的代理类Class文件在编译期生成,而动态代理的代理类Class文件在运行时生成,代理类在编译阶段并不存在,代理关系直到运行时才确定。

代码实现

静态代理

ILogger.java

package pattern.proxy.staticproxy;

/**
 * <一句话功能简述>代理模式:静态代理模式:抽象主题角色<br/>
 * <p>
 * <功能详细描述>创建一个代理类和真实类的共同接口ILogger
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public interface ILogger {
    /**
     * 功能描述: 打印日志<br>
     *
     * @author 刘斌
     * @date 2020/3/7 20:00
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    void printMessage();
}

RealLog.java

package pattern.proxy.staticproxy;

/**
 * <一句话功能简述>代理模式:静态代理模式:真实主题角色<br/>
 * <p>
 * <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class RealLog implements ILogger {

    public RealLog() {
    }

    @Override
    public void printMessage() {
        System.out.println("打印日志");
    }
}

LogProxy.java

package pattern.proxy.staticproxy;

/**
 * <一句话功能简述>代理模式:静态代理模式:代理类角色<br/>
 * <p>
 * <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class LogProxy implements ILogger {

    // 定义一个被代理类的对象
    private RealLog log;

    public LogProxy() {

    }

    // 这个构造器传入的是一个接口的对象
    public LogProxy(RealLog realLog) {
        this.log = realLog;
    }

    // 代理代理打印日志信息
    @Override
    public void printMessage() {
        preGive();
        if (null == log) {
            log = new RealLog();
        }
        log.printMessage();
        postGive();
    }

    public void preGive() {
        System.out.println("Before:在printMessage之前进行一些操作");
    }

    public void postGive() {
        System.out.println("After:在printMessage之后进行一些操作");
    }
}

StaticProxyClient.java

package pattern.proxy.staticproxy;

/**
 * <一句话功能简述>代理模式:静态代理模式:客户端调用<br/>
 * <p>
 * <功能详细描述>现在想要在不改动被代理类代码的前提下,实现对printMessage()方法前后进行操作
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class StaticProxyClient {
    public static void main(String[] args) {
        ILogger log = new LogProxy();
        log.printMessage();
    }
}

静态代理控制台输出

 

动态代理

LogUtils.java(只是工具类)

package utils;

import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * <一句话功能简述>日志打印工具类<br/>
 * <p>
 * <功能详细描述>
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class LogUtils {
    public static void startLog(Method method, Object... objects) {
        System.out.println("【" + method.getName() + "】执行开始了,他的参数为【" + Arrays.asList(objects) + "】");
    }

    public static void endLog(Method method, Object... objects) {
        System.out.println("【" + method.getName() + "】执行结束了,他的结果为【" + Arrays.asList(objects) + "】");
    }

    public static void exceptionLog(Method method, Exception e) {
        System.out.println("【" + method.getName() + "】执行出错了,错误信息为【" + e.getCause() + "】");
    }

    public static void finallyLog(Method method) {
        System.out.println("【" + method.getName() + "】最终执行结束了");
    }
}

ICalculator.java

package pattern.proxy.dynamicproxy;

/**
 * <一句话功能简述>代理模式:动态代理模式:抽象主题角色<br/>
 * <p>
 * <功能详细描述>创定义一个计算机接口
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public interface ICalculator {
    public int add(int num1, int mu2);

    public int sub(int num1, int mu2);

    public int mul(int num1, int mu2);

    public int div(int num1, int mu2);
}

MyCalculatorImpl.java

package pattern.proxy.dynamicproxy;

/**
 * <一句话功能简述>代理模式:动态代理模式:真实主题角色<br/>
 * <p>
 * <功能详细描述>被代理类
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class MyCalculatorImpl implements ICalculator {
    @Override
    public int add(int i, int j) {
        //手动为方法添加日志
        //LogUtils.startLog(i,j,"加法");
        int result;
        result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result;
        result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result;
        result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result;
        result = i / j;
        return result;
    }
}

CalculatorProxy.java

package pattern.proxy.dynamicproxy;

import utils.LogUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * <一句话功能简述>代理模式:动态代理模式:代理类角色<br/>
 * <p>
 * <功能详细描述>被代理类,现在想要在不改动被代理类代码的前提下,实现功能的扩展
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class CalculatorProxy {
    public static ICalculator getPoxy(ICalculator myCalcultor) {
        //为执行Proxy.newProxyInstance(loader, interfaces, h),三个参数赋值
        ClassLoader classLoader = myCalcultor.getClass().getClassLoader();
        Class<?>[] interfaces = myCalcultor.getClass().getInterfaces();
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //对原方法添加日志
                Object result = null;
                try {
                    LogUtils.startLog(method, args);
                    result = method.invoke(myCalcultor, args);
                    LogUtils.endLog(method, result);
                } catch (Exception e) {
                    LogUtils.exceptionLog(method, e);
                } finally {
                    LogUtils.finallyLog(method);
                }
                return result;
            }
        };
        //生成代理对象
        ICalculator proxy = (ICalculator) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
        return proxy;
    }
}

DynamicProxyClient.java

package pattern.proxy.dynamicproxy;

/**
 * <一句话功能简述>代理模式:动态代理模式:客户端调用<br/>
 * <p>
 * <功能详细描述>
 *
 * @author 刘斌
 * @date 2020/3/7
 * @see [相关类/方法](可选)
 * @since [产品/模块版本] (可选)
 */
public class DynamicProxyClient {
    public static void main(String[] args) {
        originCalc();
    }

    public static void originCalc() {
        ICalculator myCalculator = new MyCalculatorImpl();
        //int result=myCalculator.add(2, 4);

        //采用动态代理为方法添加日志
        ICalculator proxy = CalculatorProxy.getPoxy(myCalculator);
        proxy.add(2, 4);
        proxy.div(2, 1);
    }
}

动态代理控制台输出

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值