美文网首页
代理模式

代理模式

作者: zfylin | 来源:发表于2018-12-17 21:39 被阅读0次

代理(Proxy)是一种设计模式,提供了对目标对象另外的访问方式; 即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法.

角色

  1. 主题接口: 定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法
  2. 真实主题: 真正实现业务逻辑的类
  3. 代理类: 用来代理和封装真实主题

静态代理

静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
在编译期确定代理对象,在程序运行前代理类的.class文件就已经存在了

package staticproxy;
 
/**
 * 主题接口
 */
public abstract class Subject {
    public abstract void request();
}

package staticproxy;
 
/**
 * 真实主题
 */
public class RealSubject extends Subject {
 
    @Override
    public void request() {
        // TODO Auto-generated method stub
    }
 
}
package staticproxy;
 
/**
 * 静态代理,对具体真实对象直接引用
 * 代理类,代理类需要有对真实主题的引用,
 * 代理做真实主题要做的事情
 */
public class ProxySubject extends Subject {
    
    private RealSubject realSubject = null;
    
    /**
     * 除了代理真实主题做该做的事情,代理类也可以提供附加操作,
     * 如:preRequest()和postRequest()
     */
    @Override
    public void request() {
        preRequest();  //真实主题操作前的附加操作
        
        if(realSubject == null){
            realSubject =  new RealSubject();
        }
        realSubject.request();
        
        postRequest();  //真实主题操作后的附加操作
    }
 
    /**
     *  真实主题操作前的附加操作
     */
    private void postRequest() {
        // TODO Auto-generated method stub
        
    }
 
    /**
     *  真实主题操作后的附加操作
     */
    private void preRequest() {
        // TODO Auto-generated method stub
        
    }
 
}
package staticproxy;
 
/**
 *  客户端调用 
 */
public class Main {
    public static void main(String[] args) {
        Subject subject = new ProxySubject();
        subject.request();  //代理类代替真实主题实现对应业务逻辑
    }
}

优点

可以做到在不修改目标对象的功能前提下,对目标功能扩展

缺点

代理类和真实主题类实现相同的接口,同时要实现相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。

动态代理

在运行时确定代理对象

特点

  1. 在运行期,通过反射机制创建一个实现了一组给定接口的新类
  2. 在运行时生成的class,必须提供一组interface给它,然后该class就宣称它实现了这些 interface。该class的实 例可以当作这些interface中的任何一个来用。但是这个Dynamic Proxy其实就是一个Proxy, 它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工 作
  3. 接口中声明的所有方法都被转移到调用处理器一个集中的方法中处理(InvocationHandler.invoke)。这样,在接口方法数量比较多的时候,我们可以进行灵活处理,而不需要像静态代理那样每一个方法进行中转。而且动态代理的应用使我们的类职责更加单一,复用性更强

JDK中生成代理对象的API

代理类所在包:java.lang.reflect.Proxy
JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,完整的写法是:

static Object newProxyInstance(ClassLoader loader, Class [] interfaces, InvocationHandler handler)
  • ClassLoader loader: 指定当前目标对象使用类加载器,用null表示默认类加载器
  • Class [] interfaces: 需要实现的接口数组
  • InvocationHandler handler: 调用处理器,执行目标对象的方法时,会触发调用处理器的方法,从而把当前执行目标对象的方法作为参数传入

java.lang.reflect.InvocationHandler: 这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。

/**
 * 
 * 该方法负责集中处理动态代理类上的所有方法调用。
 *
 * @param proxy 代理类实例
 * @param method 被调用的方法对象
 * @param args 调用参数
 */
Object invoke(Object proxy, Method method, Object[] args)

例子


package dynamicproxy;
 
/**
 * 主题接口
 */
public interface Subject {
    void request();
}
package dynamicproxy;
 
/**
 * 真实的主题,实现主题借口
 */
public class RealSubject implements Subject {
 
    @Override
    public void request() {
        // TODO Auto-generated method stub
 
    }
}
package dynamicproxy;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
/**
 * 动态代理, 它是在运行时生成的class,在生成它时你必须提供一组interface给它, 然后该class就宣称它实现了这些interface。
 * 你当然可以把该class的实例当作这些interface中的任何一个来用。 当然啦,这个Dynamic
 * Proxy其实就是一个Proxy,它不会替你作实质性的工作, 在生成它的实例时你必须提供一个handler,由它接管实际的工作。
 */
public class DynamicSubject implements InvocationHandler {
 
    private Object sub; // 真实对象的引用
 
    public DynamicSubject(Object sub) {
        this.sub = sub;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before calling " + method); 
        method.invoke(sub,args); 
        System.out.println("after calling " + method); 
        return null; 
    }
 
}

package dynamicproxy;
 
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
 
public static void main(String[] args) {
    public static void main(String[] args) throws Throwable {
        RealSubject rs = new RealSubject();
        InvocationHandler handler = new DynamicSubject(rs);
        Class cls = rs.getClass();
        //以下是分解步骤
        /*
        Class c = Proxy.getProxyClass(cls.getClassLoader(), cls.getInterfaces());
        Constructor ct = c.getConstructor(new Class[]{InvocationHandler.class});
        Subject subject =(Subject) ct.newInstance(new Object[]{handler});
        */
        
        //以下是一次性生成
        Subject subject = (Subject)Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), handler);
        subject.request();
    }

优点

代理对象不需要实现接口,但是目标对象一定要实现接口,否则不能用动态代理。

相关文章

  • 设计模式

    单例模式 模板方法模式 工厂模式 代理模式 静态代理 JDK动态代理

  • 设计模式

    单例模式 代理模式 静态代理 jdk动态代理 cglib动态代理 工厂模式 适配器模式 建造者模式 观察者模式

  • kube-proxy的3种模式

    userspace代理模式 iptables代理模式 IPVS代理模式 https://kubernetes.io...

  • 第4章 结构型模式-代理模式

    一、代理模式简介 二、代理模式3个角色 三、代理模式的优点 四、代理模式的实例(游戏代练)

  • 理解代理模式

    原创博客地址 简介 代理模式,也叫做委托模式,分为:静态代理动态代理 代理模式也是平时比较常用的设计模式之一,代理...

  • 结构型 代理模式(文末有项目连接)

    1:什么是代理模式 2:没用代理模式时的实例 3:使用代理模式将其解耦(静态代理) 3:使用代理模式将其解耦(动态...

  • 设计模式-动态代理模式

    之前介绍了代理模式,大家也都了解了代理模式,不过之前介绍的代理模式是静态代理,静态代理什么意思?静态代理指的是代理...

  • 代理模式

    一、什么是代理模式 代理模式(Proxy pattern):代理模式又叫委托模式,是为某个对象提供一个代理对象,并...

  • 设计模式之代理模式(Proxy模式)

    代理模式的引入 代理模式的实例程序 代理模式的分析 代理模式的引入 Proxy是代理人的意思,指的是代替别人进行工...

  • Java设计模式之代理模式

    Java设计模式之代理模式 代理模式 静态代理 动态代理 为什么需要代理 通过代理,我们能够不用知道委托人是谁,而...

网友评论

      本文标题:代理模式

      本文链接:https://www.haomeiwen.com/subject/vzlhkqtx.html