设计模式:Proxy模式

Proxy模式——只在必要时生成实例

Proxy模式中,为主类创建了一个代理类,一些不一定需要主类完成的工作,可以由代理类来完成,只有代理类无法解决的任务才交由主类完成。

下面的示例程序是一个打印机的模拟。

由于打印机的初始化时间很长(假设需要的初始化时间为5秒钟),当一些不需要打印的工作来临时,交由打印机的代理类来完成,只有开始进入实际打印阶段后,才会生成打印机的实例

为了让主类和代理类具有一致性,还需要定义一个统一的接口。

下面是示例程序的具体实现。

  • 类和接口的一览表
名字 说明
Printable Printer和PrinterProxy的共同接口
Printer 表示打印机的类(主类)
PrinterProxy 表示打印机的类(代理类)
Main 测试程序行为的类
  • Printable接口
public interface Printable {
    public abstract void setPrinterName(String name);

    public abstract String getPrinterName();

    public abstract 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 + ")");
    }

    private void heavyJob(String msg) {
        System.out.println(msg);
        for (int i = 0; i < 5; i++) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.print(".");
        }
        System.out.println("结束。");
    }
    @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);
    }
}
  • PrinterProxy类
public class PrinterProxy implements Printable {
    private String name;
    private Printer real;

    public PrinterProxy() {}

    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);
        }
    }
}
  • Main类
public class Main {
    public static void main(String[] args) {
        Printable p = new PrinterProxy("1号");
        System.out.println("现在的打印机是" + p.getPrinterName());
        p.setPrinterName("2号");
        System.out.println("现在的打印机是" + p.getPrinterName());
        p.print("Hello, world.");
    }
}

示例输出如下。

现在的打印机是1号
现在的打印机是2号
正在生成Printer的实例(2号)
.....结束。
===2号===
Hello, world.

Proxy模式中的角色

  • Subject(主体)

Subject角色定义了使Proxy角色和RealSubject角色之间具有一致性的接口。由于存在Subject角色,所以Client角色不必在意它所使用的究竟是Proxy角色还是RealSubject角色。在示例程序中,由Printable接口扮演此角色。

  • Proxy(代理人)

Proxy角色会尽量处理来自Client角色的请求。只有当自己不能处理时,它才会将工作交给RealSubject角色。Proxy角色只有在必要时才会生成RealSubject角色。Proxy角色实现了在Subject角色中定义的接口(API)。在示例程序中,由PrinterProxy类扮演此角色。

  • RealSubject(实际的主体)

RealSubject角色会在Proxy角色无法解决任务时出场解决任务,它也实现了Printable接口。在示例程序中,由Printer类扮演此角色。

  • Client(请求者)

使用Proxy模式的角色。在示例程序中,由Main类扮演此角色。


Proxy模式的思路

使用代理人来提升处理速度

如果在一个大型系统的初始化过程中,存在大量的耗时处理。如果在启动系统时连那些暂时也不会被使用的功能也初始化了,那么应用程序的启动时间将会非常漫长。而如果我们只在需要使用某个功能时才将其初始化,则可以帮助我们改善用户体验。

区分代理类和主类

我们也可以不划分代理类和主类,而是直接在主类中加入惰性求值功能。但是,通过划分代理类和主类,可以使它们形成独立的组件,即使在进行修改时也不会相互影响。而且请求者可以随意地切换代理类和主类,以实现想要达到的效果。


想了解更多关于设计模式:设计模式专栏

猜你喜欢

转载自blog.csdn.net/qq_39384184/article/details/80756939
今日推荐