背景
代理模式又称为 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");
}
}
功能分析
- 提升处理速度,可以将耗时的操作在某个功能实现时才进行初始化,即 Proxy角色调用RealSubject中的方法;
- 提高灵活性,如果不想使用 Proxy 中的方法,可以直接创建 RealSubject 对象,因为他们都实现了同一个接口;
- 但是如果需要代理多个类,那么每一个类都会有一个代理类,会导致代理类无限地扩展,同时一旦接口增加方法,目标对象和代理对象都要进行修改;
分类
静态代理
在编译时就已经实现,编译完后代理类就是一个class文件。就是上述的例子
动态代理
在运行时动态生成,运行时动态生成字节码文件,并加载到JVM中,作者水平不足,无法分析实例;