博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Proxy模式(代理[延迟]模式)
阅读量:5218 次
发布时间:2019-06-14

本文共 6279 字,大约阅读时间需要 20 分钟。

Proxy??

Proxy是“代理人”的意思,它指的是代替别人进行工作的人。代理实际上就是使用委托的机制,在代理的过程中你可以做点其他的事情,然后再来执行被代理对象的代码。

  • 知识储备

1.什么时候使用:

GoF书(请参见附录E[GoF])在讲解Proxy模式时,使用了一个可以在文本中嵌入图形对象(例如图片等)的文本编辑器作为例子。为了生成这些图形对象,需要读取图片文件,这很耗费时间。因此如果在打开文档时就生成有所的图形对象,就会导致文档打开时间过长。所以,最好是当用户浏览至文本中各个图形对象时,再去生成它们的实例。这时,Proxy模式就有了用武之地。

2.有那些代理:

  • Virtual Proxy(虚拟代理)Virtual Proxy就是本章中学习的Proxy模式。只有当真正需要实例时,它才生成和初始化实例。
  • Remote Proxy(远程代理)Remote Proxy可以让我们完全不必在意RealSubject角色是否在远程网络上,可以如同它在自己身边一样(透明性地)调用它的 方法。Java的RMI(RemoteMethodInvocation:远程方法调用)就相当于Remote Proxy。
  • Access Proxy Access Proxy 用于在调用RealSubject角色的功能时设置访问限制。例如,这种代理可以只允许指定的用户调用方法,而当其他用户调用方法时则报错。

  • 静态代理

    1.使用委托机制代理人只代理他能解决的问题。当遇到他不能解决的问题时,还是会“转交”给本人去解决。
    这里的“转交”就是在本书中多次提到过的“委托”。从PrinterProxy类的print方法中调用real.print方法正是这种“委托”的体现。

  1. 为了实现PrinterProxy类可以从printer类中分离出来作为独立的组件使用,而且只要是实现了Printable接口的类都可以扮演Proxy的角色。需要使用反射实例
private synchronized void realize(String classname) {    if(real==null){        try {            real = ((Printable) Class.forName(classname).newInstance());        }catch (ClassNotFoundException e){            System.out.println("没有发现"+classname);        }catch (Exception e){            e.printStackTrace();        }    }}
  • 动态代理

在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。首先我们先来看看java的API帮助文档是怎么样对这两个类进行描述的:

InvocationHandler:

InvocationHandler is the interface implemented by the invocation handler of a proxy instance. Each proxy instance has an associated invocation handler. When a method is invoked on a proxy instance, the method invocation is encoded and dispatched to the invoke method of its invocation handler.

每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看

InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable

我们看到这个方法一共接受三个参数,那么这三个参数分别代表什么呢?

Object invoke(Object proxy, Method method, Object[] args) throws Throwableproxy:  指代我们所代理的那个真实对象method:  指代的是我们所要调用真实对象的某个方法的Method对象args:  指代的是调用真实对象某个方法时接受的参数

理清职责

  • 实现一个带名字的打印机
    名字=====》》说明
    Printer || 表示带名字的打印机的类(本人)
    Printable || Printer和PrinterProxy的共同接口
    PrinterProxy || 表示带名字的打印机的类(代理人)
    Main ||测试程序行为的类

UML

1160484-20181102230317076-976163396.png

类图:

1160484-20181102230321697-312367728.png

时序图:

1160484-20181102230324950-769563390.png

Code

  • Printable
public interface Printable {    // 设置打印名字    void setPrinterName(String name);    // 获取打印名字    String getPrinterName();    // 显示文字    void print(String string);}
  • Printer

···

public class Printer implements Printable{
private String name;

public Printer() {    heavyjob("正在生成Printer实例");}public Printer(String name) {    this.name = name;    heavyjob("正在生成Printer实例("+name+")");}/** * 模拟一个高负载任务 * @param string */private void heavyjob(String string) {    System.out.println(string);    for (int i = 0; i < 5; i++) {        try {            Thread.sleep(1000);        }catch (InterruptedException e){            e.printStackTrace();        }        System.out.print(".");    }}@Overridepublic void setPrinterName(String name) {    this.name=name;}@Overridepublic String getPrinterName() {    return name;}@Overridepublic void print(String string) {    System.out.println("==="+name+"===");    System.out.println(string);}

}

···

  • PrinterProxy
public class PrinterProxy implements Printable{    private String name;    private Printer real;    /**     * 不论 setPrinterName 方法和getPrinterName 方法被调用多少次,     * 都不会生成Printer类的实例。只有当真正需要本人时,     * 才会生成printer类的实例(printerProxy类的调用者完全不知道是否生成了本人,也不用在意是否生成了本人)。     * @param name     */    public PrinterProxy(String name) {        this.name = name;    }    @Override    public synchronized void setPrinterName(String name) {        if(real!=null){            real.setPrinterName(name);        }        this.name=name;    }    @Override    public String getPrinterName() {        return name;    }    @Override    public void print(String string) {            realize();            real.print(string);    }    private synchronized void realize() {        if(real==null) real=new Printer(name);    }}public class MainT {    public static void main(String[] args) {        Printable p=new PrinterProxy("Tom");        System.out.println("现在是"+p.getPrinterName());        p.setPrinterName("Cat");        System.out.println("现在是"+p.getPrinterName());        p.print("我是 Tomcat");    }}
  • 结果:
现在是Tom现在是Cat正在生成Printer实例(Cat).....===Cat===我是 Tomcat

动态代理Code

public class Client {    public static void main(String[] args) {        Printable tom = new Printer("Tom");        DynamicProxy proxy = new DynamicProxy(tom);        Printable o = (Printable) Proxy.newProxyInstance(proxy.getClass().getClassLoader(),                tom.getClass().getInterfaces(), proxy);        System.out.println(o.getClass().getName());        System.out.println("现在是"+o.getPrinterName());        o.print("Tomcat");    }}public class DynamicProxy implements InvocationHandler {    private Object object;    public DynamicProxy(Object object) {        this.object = object;    }    @Override    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("准备执行");        System.out.println("Method:" + method);        Object o = method.invoke(object, args);        System.out.println("执行完毕");        return o;    }}public interface Printable {    // 设置打印名字    void setPrinterName(String name);    // 获取打印名字    String getPrinterName();    // 显示文字    void print(String string);}public class Printer implements Printable{    private String name;    public Printer() {        heavyjob("正在生成Printer实例");    }    public Printer(String name) {        this.name = name;        heavyjob("正在生成Printer实例("+name+")");    }    /**     * 模拟一个高负载任务     * @param string     */    private void heavyjob(String string) {        System.out.println(string);        for (int i = 0; i < 5; i++) {            try {                Thread.sleep(1000);            }catch (InterruptedException e){                e.printStackTrace();            }            System.out.print(".");        }    }    @Override    public void setPrinterName(String name) {        this.name=name;    }    @Override    public String getPrinterName() {        return name;    }    @Override    public void print(String string) {        System.out.println("==="+name+"===");        System.out.println(string);    }}

转载于:https://www.cnblogs.com/dgwblog/p/9899023.html

你可能感兴趣的文章
高级滤波
查看>>
使用arcpy添加grb2数据到镶嵌数据集中
查看>>
[转载] MySQL的四种事务隔离级别
查看>>
QT文件读写
查看>>
C语言小项目-火车票订票系统
查看>>
15.210控制台故障分析(解决问题的思路)
查看>>
BS调用本地应用程序的步骤
查看>>
常用到的多种锁(随时可能修改)
查看>>
用UL标签+CSS实现的柱状图
查看>>
mfc Edit控件属性
查看>>
Linq使用Join/在Razor中两次反射取属性值
查看>>
[Linux]PHP-FPM与NGINX的两种通讯方式
查看>>
Java实现二分查找
查看>>
优秀员工一定要升职吗
查看>>
[LintCode] 462 Total Occurrence of Target
查看>>
springboot---redis缓存的使用
查看>>
架构图-模型
查看>>
sql常见面试题
查看>>
jQuery总结第一天
查看>>
Java -- Swing 组件使用
查看>>