java设计模式-代理模式

简介

定义

代理模式定义:给某一个对象提供一个代理,通过代理来控制对该对象的引用。

相关角色

Subject: 抽象主题角色接口。是RealSubject和Proxy的共用接口。

RealSubject: 真实主题角色,实现了Subject接口。

Proxy: 代理角色,内部有RealSubject的引用,因此可操作RealSubject。同时代理对象提供了真实对象拥有的接口,因此在任何时刻都能替代RealSubject。并且通过代理对象执行RealSubject的操作前后进行处理。

代理类型:

1.静态代理

静态代理由程序员创建或由特定工具自动生成代理类的源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。

实现静态代理的两种方法:

聚合式静态代理

聚合式静态代理模式UML类图

 实现代码:

/**
 * Subject 
 * 抽象主题接口
 * @author
 * @create 2018-03-29 14:16
 **/
public interface Subject {

    void doSomething();
}
/**
 * RealSubject
 * 真实主题类
 * @author
 * @create 2018-03-29 14:21
 **/
public class RealSubject implements Subject {
    @Override
    public void doSomething() {
        System.out.println("RealSubject do something");
    }
}
/**
 * Proxy
 * 代理类
 * @author
 * @create 2018-03-29 14:22
 **/
public class Proxy implements Subject {

    // 以聚合方式实现代理
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void doSomething() {
        System.out.println("Do something before");
        realSubject.doSomething();
        System.out.println("Do something after");
    }
}
/**
 * Client
 * client测试代码
 * @author
 * @create 2018-03-29 14:26
 **/
public class Client {
    public static void main(String[] args) {
        // 聚合式静态代理测试
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.doSomething();


    }
}
继承式静态代理

继承式静态代理模式UML类图

 

实现代码:

抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。

/**
 * Proxy2
 * 代理类
 * @author
 * @create 2018-03-29 15:02
 **/
public class Proxy2 extends RealSubject {

    @Override
    public void doSomething() {
        System.out.println("Do something before");
        super.doSomething();
        System.out.println("Do something after");
    }
}
/**
 * Client
 * client测试代码
 * @author
 * @create 2018-03-29 14:26
 **/
public class Client {
    public static void main(String[] args) {
        
        // 继承式静态代理测试
        Proxy2 proxy2 = new Proxy2();
        proxy2.doSomething();

    }
}

 聚合方式先比继承方式更加灵活。

 静态代理一般是一个真实主题类对应一个代理类,当抽象主题接口存在多个主题实现类时,对应的代理类也会逐渐增多。这时候如果想要一个代理类能代理多个实现类的话,

则需要使用动态代理进行处理。

2.动态代理

动态代理指的是代理类由程序在运行时动态生成,不用手动编写。

动态代理实现的几种方式:jdk动态代理、cglib动态代理

jdk动态代理

实现代码:

抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。

/**
 * JDKDynamicProxy
 * jdkd动态代理
 *
 * @author
 * @create 2018-03-29 16:17
 **/
public class JDKDynamicProxy implements InvocationHandler {

    private Object target;

    public JDKDynamicProxy(Object target) {
        this.target = target;
    }

    public <T> T getProxy() {
        return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Do something before");
        Object result = method.invoke(target, args);
        System.out.println("Do something after");
        return result;
    }
}
/**
 * Client
 * client测试代码
 * @author
 * @create 2018-03-29 14:26
 **/
public class Client {
    public static void main(String[] args) {
        
        // jdk动态代理测试
        Subject subject = new JDKDynamicProxy(new RealSubject()).getProxy();
        subject.doSomething();

    }
}

jdk动态代理支持一个代理类可以代理多个主题实现类的问题,但是还有一个问题就是只能动态代理接口,而不能代理不是接口的类。

cglib动态代理

实现代码:

 抽象主题接口类Subject和真实主题类RealSubject与聚合方式中的相同,不再复制。

此处选用spring框架中的cglib实现。

/**
 * Fish
 * 真实主题类
 * @author
 * @create 2018-03-29 17:00
 **/
public class Fish {

    public void swim() {
        System.out.println("Do you like swimming");
    }
}
/**
 * CGLibDynamicProxy
 * cglib动态代理
 * @author
 * @create 2018-03-29 16:37
 **/
public class CGLibDynamicProxy implements MethodInterceptor {

    private static CGLibDynamicProxy instance = new CGLibDynamicProxy();

    public static CGLibDynamicProxy getInstance() {
        return instance;
    }

    public <T> T getProxy(Class<T> cls) {
        return (T) Enhancer.create(cls, this);
    }

    @Override
    public Object intercept(Object target, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("Do something before");
        Object result = methodProxy.invokeSuper(target, args);
        System.out.println("Do something after");
        return result;
    }
}
/**
 * Client
 * client测试代码
 * @author
 * @create 2018-03-29 14:26
 **/
public class Client {
    public static void main(String[] args) {

        // cglib动态代理测试
        Fish fish = CGLibDynamicProxy.getInstance().getProxy(Fish.class);
        fish.swim();
    }
}

 cglib可以代理没有接口的类。

参考资料:https://juejin.im/entry/595f53835188250d920875e3

原文地址:https://www.cnblogs.com/zuidongfeng/p/8670200.html