代理模式(Proxy Pattern)

2018-08-14  本文已影响0人  luoqiang108

1.介绍

1.1定义

代理模式的定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。

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

1.2作用

1.3静态代理&动态代理

我们有多种不同的方式来实现代理。如果按照代理创建的时期来进行分类的话, 可以分为两种:静态代理、动态代理。静态代理是由程序员创建或特定工具自动生成源代码,在对其编译。在程序员运行之前,代理类.class文件就已经被创建了。动态代理是在程序运行时通过反射机制动态创建的。

2.模式原理

2.1 UML类图 & 讲解 代理模式UML.png

讲解:

  1. 抽象对象角色:声明了目标类及代理类对象的共同接口,这样在任何可以使用目标对象的地方都可以使用代理对象。
  2. 目标对象角色(真实对象角色):定义了代理对象所代表的目标对象。
  3. 代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象和目标对象具有统一的接口,以便可以再任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或者之后,执行某些操作,而非单纯的将调用传递给目标对象。
  4. 实现动态代理的关键技术是反射。

3.静态代理

a. 实例概况

代购(代理对象) 代替 我(真实对象) 去买Mac(间接访问的操作)

b.使用步骤

步骤1: 创建抽象对象接口(AbstractObject):声明你(真实对象)需要让代购(代理对象)帮忙做的事(买Mac)
public interface AbstractObject {
    void buyMac();
}
步骤2: 创建真实对象类(RealObject ),即“我”
public class RealObject implements AbstractObject{
    @Override
    public void buyMac() {
        System.out.println("买一台Mac");
    }
}
步骤3:创建代理对象类(ProxyObject ),即“代购”,并通过代理类创建真实对象实例并访问其方法
public class ProxyObject implements AbstractObject{
    private AbstractObject abstractObject;
    public ProxyObject(AbstractObject abstractObject) {
        this.abstractObject = abstractObject;
    }
    @Override
    public void buyMac() {
        //调用真实对象的方法,进行代理购买Mac
        abstractObject.buyMac();
        //代理对象额外做的操作
        this.WrapMac();
    }
    private void WrapMac() {
        System.out.println("用盒子包装好Mac");
    }
}
步骤4:客户端调用
public class ProxyPattern {
    public static void main(String[] args){
        RealObject realObject = new RealObject();
        ProxyObject proxyObject = new ProxyObject(realObject);
        proxyObject.buyMac();
    }
}
输出结果
买一台Mac
用盒子包装好Mac

c. 优点

d. 缺点

4.JDK动态代理

一般来说,对代理模式而言,一个主题类与一个代理类一一对应,这也是静态代理模式的特点。但是,也存在这样的情况,有n各主题类,但是代理类中的“前处理、后处理”都是一样的,仅调用主题不同。也就是说,多个主题类对应一个代理类,共享“前处理,后处理”功能,动态调用所需主题,大大减小了程序规模,这就是动态代理模式的特点。

a. 实例概况

统计行驶时间

步骤1: 抽象主题
public interface Moveable {
    void move() throws Exception;
}
步骤2: 真实主题
import java.util.Random;
public class Car implements Moveable {
    @Override
    public void move() throws Exception {
        Thread.sleep(new Random().nextInt(1000));
        System.out.println("汽车行驶中…");
    }
}
步骤3:事务处理器
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimeHandler implements InvocationHandler {
    private Object target;
    public TimeHandler(Object target) {
        this.target = target;
    }
    /**
     * 参数:
     * @param proxy 被代理的对象
     * @param method 被代理对象的方法
     * @param args 方法的参数
     * @return Object 方法返回值
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        long startTime = System.currentTimeMillis();
        System.out.println("汽车开始行驶…");
        method.invoke(target, args);
        long stopTime = System.currentTimeMillis();
        System.out.println("汽车结束行驶…\n汽车行驶时间:" + (stopTime - startTime) + "毫秒!");
        return null;
    }
}
步骤4:测试类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class ProxyPattern {
    public static void main(String[] args){
        try {
            Car car = new Car();
            InvocationHandler h = new TimeHandler(car);
            Class<?> cls = car.getClass();
            /**
             *loader 类加载器(要进行代理的类)
             *interfaces 被代理类实现的接口
             *h InvocationHandler 事务处理器
             */
            Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);
            //执行目标对象的方法,会触发事件处理器的invoke方法
            m.move();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
输出结果
汽车开始行驶…
汽车行驶中…
汽车结束行驶…
汽车行驶时间:44毫秒!

b.优点

c.缺点(有点懵大概了解下吧,有实力再去看源码深入)

JDK的动态代理类是继承了Proxy类的,所以使用JDK动态代理不能实现继承式动态代理,原因是Java不允许多继承,而生成的代理类本身就已经继承了Proxy类。

5.CGLIB代理(在Spring、Hibernate等很多服务器框架中使用,所以也涉及了很多那方面知识,自己实力不够,仅记录下来做个参考,代码也是跑不通的,会报错)

步骤1:具体主题
public class Train {
    public void move(){
        System.out.println("火车行驶中…");
    }
}
步骤2:生成代理
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CGLibProxy implements MethodInterceptor {
    private Enhancer enhancer = new Enhancer();
    public Object getProxy(Class<?> clazz){
        enhancer.setSuperclass(clazz);
        enhancer.setCallback(this);
        return enhancer.create();
    }
    /**
     * 拦截所有目标类方法的调用
     * 参数:
     * obj目标实例对象
     *method 目标方法的反射对象
     * args方法的参数
     * proxy代理类的实例
     */
    public Object intercept(Object obj, Method method, Object[] args,
                            MethodProxy proxy) throws Throwable {
        //代理类调用父类的方法
        System.out.println("开始…");
        proxy.invokeSuper(obj, args);
        System.out.println("结束…");
        return null;
    }
}
步骤3:测试类
public class ProxyPattern {
    public static void main(String[] args){
        CGLibProxy proxy = new CGLibProxy();
        Train t = (Train) proxy.getProxy(Train.class);
        t.move();
    }
}
步骤4:输出结果
开始…
火车行驶中…
结束…

6.小结

7.感谢

代理模式(Proxy Pattern):静态代理 - 最易懂的设计模式解析
Java设计模式——代理模式实现及原理
设计模式---代理模式

上一篇下一篇

猜你喜欢

热点阅读