设计模式之结构型模式(代理模式)

基本介绍 – 只在必要时生成实例

  1. 代理模式:为一个对象提供一个替身,以控制对这对象的访问。即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。
  2. 被代理的对象可以是远程对象、创建开销大的对象需要安全控制的对象
    只在必要时生成实例,我在看网上的详解中,大部分没有提到这句话,只讲了代理而已。
    在面向对象编程中,“本人”(被代理)和“代理人”(代理)都是对象,如果“本人”对象太忙了,有些工作无法亲自完成,就将其交给“代理人”对象负责。

示例程序
实现一个带名字的打印机,说是打印机,只是将文字显示在界面上而已。

类和接口一览表:

  • Printer:表示带名字的打印机(被代理)
  • Printable:Printer和PrintProxy的共同接口
  • PrintProxy:表示带名字的打印机(代理人)
  • Main;测试程序行为的类

类图:
在这里插入图片描述
时序图:
在这里插入图片描述
Printer:表示带名字的打印机(被代理)

public class Printer implements Printable{
	//打印机的名字
    private String name;
	//构造方法内做一些“重活”,表示“本人”对象太忙了。。
    public Printer() {
        heavyJob("Print实例生成中");
    }

    public Printer(String name) {
        this.name = name;
        heavyJob("Print实例生成中(" + name + ")");
    }
    @Override
    public void setPrintName(String name){
        this.name = name;
    }
    @Override
    public String getPrintName(){
        return name;
    }
    //显示一串打印机的名字和打印内容
    @Override
    public void print(String string){
        System.out.println("=== " + name + " ===");
        System.out.println(string);
    }
	//sleep方法,表示5秒的“重活”
    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.println("结束。");
    }
}

Printable:Printer和PrintProxy的共同接口

public interface Printable {
    void setPrintName(String name);
    String getPrintName();
    void print(String string);
}

PrintProxy:表示带名字的打印机(代理人),不论setPrintName和getPrintName方法别调用多少次,都不会生成Printer实例,只有调用代理人无法完成的print方法时,才会生成实例。
Print类并不知道PrintProxy类的存在,即,Printer类不知道自己到底是通过PrinterProxy调用还是直接被调用的
但反过来,PrinterProxy类是知道Printer类的,这是因为Printer类是PrinterProxy类的字段,显式的写出了Printer这个类名,Printer和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 setPrintName(String name) {
    	//当打印机对象存在时,需将打印机对象内的名字一起同步更新
        if(real != null){
            real.setPrintName(name);
        }
        this.name = name;
    }

    @Override
    public String getPrintName() {
        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 proxy = new PrinterProxy("Alice");
        System.out.println(proxy.getPrintName());
        proxy.setPrintName("Job");
        System.out.println(proxy.getPrintName());
        proxy.print("Hello, world");
    }
}

适用场景:

  • 延迟初始化 (虚拟代理)。 如果你有一个偶尔使用的重量级服务对象, 一直保持该对象运行会消耗系统资源时, 可使用代理模式。你无需在程序启动时就创建该对象, 可将对象的初始化延迟到真正有需要的时候。
  • HTTP代理。通过浏览器区访问Web界面,并不会每次都去访问Web服务器来获取页面,而是先去获取HTTP代理缓存的页面。只有当需要最新页面或页面的缓存期限过期时,才回去访问远程Web服务器。
  • 访问控制 (保护代理)。 如果你只希望特定客户端使用服务对象, 这里的对象可以是操作系统中非常重要的部分, 而客户端则是各种已启动的程序 (包括恶意程序), 此时可使用代理模式。 代理可仅在客户端凭据满足要求时将请求传递给服务对象。
  • 记录日志请求 (日志记录代理)。 适用于当你需要保存对于服务对象的请求历史记录时。 代理可以在向服务传递请求前进行记录。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值