设计模式——代理模式

Posted 刘永祥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式——代理模式相关的知识,希望对你有一定的参考价值。

代理对于我们来说再熟悉不过了,比如:代理商,代理律师。那么代理的到底是什么含义呢?代理就是受委托代表当事人进行某种活动。那么代理模式的核心作用是什么呢?就是通过代理,控制对象的访问。可以详细的控制访问某个或者是某类对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。
代理是在需要用比较通用和复杂的对象指针代替简单的指针的时候,使用代理模式。
下面是一些可以使用代理 模式常见情况:
1.远程代理为一个对象在不同的地址空间提供局部代表。
2.虚代理根据需要创建开销很大的对象,使得此对象只在需要时才会真正创建。
3.保护代理控制对原始对象的访问。
4.智能指引取代了简单的指针,它在访问对象时执行一些附加操作。
5.防火墙代理,保护目标,不让恶意用户接近。
代理又分为静态代理(静态定义代理类)和动态代理(动态生成代理类)两种。
动态代理相比较静态代理而言在抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样的好处就是我们可以更加灵活和统一的处理众多的方法。
举个例子:假如说我在北京工作,接了一个上海的项目,但是由于太远我又不想去上海,怎么办呢?此时刚好我一个同学在上海上班,于是我就跟我的同学联系,让他帮我把这个项目谈过来。接项目肯定需要 面谈—>起草合同—>收首款—>做项目—>收尾款。除了完成项目的过程是由我本人执行之外,其他的都是由我同学来处理的,那么我同学所起的作用就是代理。
静态代理模式为
接项目过程

public interface Project 
    String interview();
    String drafContract();
    String receiveFirst();
    String doProjects ();
    String endParagraph();

本人自己

public class Mine implements Project 
    @Override
    public String interview() 
        return "Mine--->interview";
    

    @Override
    public String drafContract() 
        return "Mine--->drafContract";
    

    @Override
    public String receiveFirst() 
        return "Mine--->receiveFirst";
    

    @Override
    public String doProjects() 
        return "Mine--->doProjects";
    

    @Override
    public String endParagraph() 
        return "Mine--->endParagraph";
    

同学代理

public class ProxySchoolmate  implements Project
    private Mine mine;

    public ProxySchoolmate(Mine mine) 
        this.mine = mine;
    

    @Override
    public String interview() 
        return "ProxySchoolmate--->interview";
    

    @Override
    public String drafContract() 
        return "ProxySchoolmate--->drafContract";
    

    @Override
    public String receiveFirst() 
        return "ProxySchoolmate--->receiveFirst";
    

    @Override
    public String doProjects() 
        return  mine.doProjects();
    

    @Override
    public String endParagraph() 
        return "ProxySchoolmate--->endParagraph";
    

测试

  Mine mine = new Mine();
  ProxySchoolmate proxySchoolmate = new ProxySchoolmate(mine);
  System.out.println(proxySchoolmate.interview());
  System.out.println(proxySchoolmate.drafContract());
  System.out.println(proxySchoolmate.receiveFirst());
  System.out.println(proxySchoolmate.doProjects());
  System.out.println(proxySchoolmate.endParagraph());

运行效果

动态代理模式为
接项目过程和本人自己的内容完全相同,不同的是同学代理少了构造方法,多了一个动态代理机制的类
同学代理

public class ProxySchoolmate implements Project 

    @Override
    public String interview() 
        return "ProxySchoolmate--->interview";
    

    @Override
    public String drafContract() 
        return "ProxySchoolmate--->drafContract";
    

    @Override
    public String receiveFirst() 
        return "ProxySchoolmate--->receiveFirst";
    

    @Override
    public String doProjects() 
        return "ProxySchoolmate--->doProjects";
    

    @Override
    public String endParagraph() 
        return "ProxySchoolmate--->endParagraph";
    

动态代理机制类

public class ProjectHandler implements InvocationHandler 
    Mine mine;
    ProxySchoolmate proxySchoolmate = new ProxySchoolmate();
    public ProjectHandler(Mine mine) 
        this.mine = mine;
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable 
        System.out.println(proxySchoolmate.interview());
        System.out.println(proxySchoolmate.drafContract());
        System.out.println(proxySchoolmate.receiveFirst());
        if (method.getName().equals("doProjects")) 
            proxy = method.invoke(mine, objects);
            System.out.println(proxy.toString());
        
        System.out.println(proxySchoolmate.endParagraph());
        return proxy;
    

测试

Mine mine = new Mine();
ProjectHandler handler = new ProjectHandler(mine);
Project project = (Project) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]Project.class,handler);
project.doProjects();

运行效果与上面的运行效果相同。
下面来说一下动态代理机制
动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(接口)、另一个则是 Proxy(类),这一个接口和一个类是实现我们动态代理必不可少的。上面的使用也许大家已经看到了。如果我们要实现一个动态代理类首先必须要实现InvocationHandler这个接口,而且这个代理类实例需要关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转化为由InvocationHandler这个接口的 invoke 方法来进行调用。上面的ProjectHandler 这个类就是最好的证明。那么invoke(Object proxy, Method method, Object[] objects) throws Throwable 这个方法里面的三个参数各代表什么呢?
proxy:就是我们所代理的那个真实对象
method:就是我们所要调用真实对象的某个方法的Method对象
objects:就是调用真实对象某个方法时接受的参数
Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法,源码为

public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException 

我们使用时为Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),new Class[]Project.class,handler)这个方法里面也有三个参数,各代表什么呢?
loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上。
好了动态代理到此也就结束了,整个代理模式也就到这里了。

以上是关于设计模式——代理模式的主要内容,如果未能解决你的问题,请参考以下文章

java设计模式--代理模式

设计模式——代理模式

静态代理模式

代理模式

5 分钟带你了解 HTTP 代理

设计模式 结构型模式 -- 代理模式(代理模式概述结构静态代理动态代理)