代理模式
给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
角色
- 抽象主体(Subject)
代理对象和实际对象的统一性接口 - 代理者(Proxy)
包含了对实际主体的引用。 - 实际主体(RealSubject)
当代理者无法胜任时,才可由使用者直接操纵
案例
代理打印机
代码
Printer:Subject
public interface Printer {
public void setName(String printerName);
public String getName();
public void print(String content) throws InterruptedException;
}
RealPrinter: RealSubject
public class RealPrinter implements Printer{
private String name;
/**
* 定义启动需要5秒
* @param name
* @throws InterruptedException
*/
public RealPrinter(String name) throws InterruptedException {
System.out.printf("正在初始化打印机");
Thread.sleep(5000);
this.name = name;
System.out.println("初始化完成");
}
@Override
public void setName(String printerName) {
this.name = printerName;
}
@Override
public String getName() {
return this.name;
}
@Override
public void print(String content) {
System.out.printf("=== %s ===\n", this.name);
System.out.println(content);
System.out.println("==========");
}
}
PrinterProxy: Proxy
/**
* 代理打印机代理了返回名字的工作,打印工作人需要实际打印机
*/
public class PrinterProxy implements Printer{
private String name;
private RealPrinter realPrinter;
public PrinterProxy(String name){
setName(name);
}
@Override
public void setName(String printerName) {
this.name = printerName;
if (realPrinter!=null) {
realPrinter.setName(printerName);
}
}
@Override
public String getName() {
return name;
}
@Override
public void print(String content) throws InterruptedException {
realize();
realPrinter.print(content);
}
private synchronized void realize() throws InterruptedException {
if (realPrinter==null){
realPrinter = new RealPrinter(name);
}
}
}
Main:
public class Main {
public static void main(String[] args) throws InterruptedException {
Printer printer = new PrinterProxy("Printer");
System.out.printf("Printer's name is %s.\n", printer.getName());
printer.print("Hello, world!");
}
}
剖析
在这个案例中,使用PrinterProxy有什么优势?只有在真正需要打印的时候,才会实例化打印机,消耗那5秒,否则即便你不需要打印东西,只需要知道打印机的名字,new一个真打印机也不得不消耗那5秒。
权限控制
这个案例就不写代码了,想象一下即可,假设一个资源作为RealSubject,只有管理员才能访问,那么通过Proxy访问时资源时,要额外传入你的身份令牌,Proxy会先检验你的权限,然后再决定是否访问资源。
应用场景
- 虚拟代理(Virtual Proxy),用于减轻一个庞大的软件系统初始化
- 远程代理(Remote Proxy),用于远程调用代理
- 通道代理(Access Proxy),用于调用RealSubject时的权限控制