代理模式

234 阅读2分钟

背景

代理模式又称为 Proxy 模式,Proxy 是代理人的意思,它指的是代替别人进行工作的人,当不一定需要本人亲自进行工作时,就可以寻找代理人去完成工作。但如果代理人实现不了,就需要寻找本人去解决问题。

登场角色

Subject 主体

Subject角色定义了使 Proxy 角色和 RealSubject 角色之间的一致性接口,由于存在Subject角色,所以Client角色不必在意他使用的究竟是Proxy角色还是RealSubject角色

Proxy 代理人

Proxy角色会尽量处理来自Client角色的请求。只有当自己不能处理时,它才会将工作交给RealSubject来处理,Proxy角色只有在必要时才会生成RealSubject角色,Proxy角色实现了在Subject角色中定义的接口

RealSubject 实际的主体

RealSubject 角色会在 Proxy角色无法胜任工作时登场,它也实现了 Subject角色中定义的接口

Client 请求者

使用 Proxy模式的角色

类图

示例代码

以打印名称为例,proxy中存在设置名称和获取名称的作用,而realsubject中就存在打印名称的作用

Printable 接口

public interface Printable {

    String getPrinterName();

    void setPrinterName(String name);

    void print(String print);
}

Printer类 相当于 RealSubject

public class Printer implements Printable{

    private String name;

    public Printer() {
        heavy();
    }

    public Printer(String name) {
        heavy();
        this.name = name;
    }

    @Override
    public String getPrinterName() {
        return this.name;
    }

    @Override
    public void setPrinterName(String name) {
        this.name = name;
    }

    @Override
    public void print(String print) {
        System.out.println("=========" + name + "==========");
        System.out.println(print);
    }


    private void heavy() {
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print(".");
        }
        System.out.println();
    }
}

PrintProxy类 相当于Proxy类

public class PrinterProxy implements Printable {

    private String name;

    private Printer printer;

    public PrinterProxy() {
    }

    public PrinterProxy(String name) {
        this.name = name;
    }

    @Override
    public String getPrinterName() {
        return this.name;
    }

    @Override
    public synchronized void setPrinterName(String name) {
        if (printer != null) {
            printer.setPrinterName(name);
        }
        this.name = name;
    }

    @Override
    public void print(String print) {
        realize();
        printer.print(print);
    }

    public synchronized void realize() {
        if (printer == null) {
            printer = new Printer(this.name);
        }
    }
}

Main类

public class Main {
    public static void main(String[] args) {
        PrinterProxy printerProxy = new PrinterProxy("ezreal");
        System.out.println("现在的名称为:" + printerProxy.getPrinterName());
        printerProxy.setPrinterName("lwj");
        System.out.println("现在的名称为:" + printerProxy.getPrinterName());

        printerProxy.print("EzreaLwj");
    }
}

功能分析

  1. 提升处理速度,可以将耗时的操作在某个功能实现时才进行初始化,即 Proxy角色调用RealSubject中的方法;
  2. 提高灵活性,如果不想使用 Proxy 中的方法,可以直接创建 RealSubject 对象,因为他们都实现了同一个接口;
  3. 但是如果需要代理多个类,那么每一个类都会有一个代理类,会导致代理类无限地扩展,同时一旦接口增加方法,目标对象和代理对象都要进行修改;

分类

静态代理

在编译时就已经实现,编译完后代理类就是一个class文件。就是上述的例子

动态代理

在运行时动态生成,运行时动态生成字节码文件,并加载到JVM中,作者水平不足,无法分析实例;