淘先锋技术网

首页 1 2 3 4 5 6 7

代理模式

给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

角色

  • 抽象主体(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时的权限控制