• 4、代理模式与静态代理


    下面从图上面来理解代理模式:

    如上图,有一套接口ISubject,其实现类是SubjectImpl。

    通常情况下采用面向接口编程,new 一个SubjectImpl并将其赋值给ISubject类型的引用,后续都通过接口类型的引用来调用实现类的具体方法。这是“面向接口编程”和“多态”的实际应用。如下:

    code1:

    ISubject sub = new SubjectImpl();    //实现类对象赋值给接口引用
    sub.request();   //通过接口调用方法

     代理模式通常涉及到4种角色:

    1、ISubject。接口,是被访问资源的抽象。

    2、SubjectImpl。具体的实现类,者是被访问资源的具体实现类。

    3、SubjectProxy。被访问资源的代理实现类,注意:该类中持有一个ISubject接口的具体实例。如上图中,SubjectProxy要对SubjectImpl实现类进行代理,那么其持有的具体实例就是SubjectImpl。

    4、Client。代表访问者的抽象角色,Client会访问ISubject类型的对象或资源。

    我们应该要注意到:SubjectImpl和SubjectProxy都实现了公共的接口ISubject,而SubjectProxy内部持有一个SubjectImpl(或者是ISubject接口的其它实现类)的引用。当Client调用request()方法访问资源的时候,SubjectProxy会通过其内部的持有对象将请求转发给SubjectImpl来执行。

    但从请求的角度来看,这似乎是一个多余的过程,还没有code1来得简单直接。为什么还要这么做呢??

    现在我们给request()方法执行加一个条件:每天的0点到6点之间,系统不接受Client的request()。

    解决方案1:在code1调用sub.request()之前判断

     1 ISubject sub = new SubjectImpl();
     2 
     3 Date start = DateUtils.timeOfDay(0,0,0);    //时间0点
     4 Date end = DateUtils.timeOfDay(6,0,0);    //6点
     5 Date end = new Date();
     6 if(now.after(start)&&now.before(end)){
     7     System.out.println("系统维护时间,禁止请求...");
     8     return null;    //不会执行被代理对象的实际方法
     9 }else{
    10     sub.request();   //特定时间之外执行请求  
    11 }

    这样做当然能实现,但是我们必须在工程中所有调用sub.request()的地方都写上这么多冗余的代码,如果有一天时间从6点推迟到7点了,那么我们必须手动的修改散落在各个角落的源代码,维护成本很高。

    有童鞋说,好办,修改下SubjectImpl的源代码不就什么事情都解决了吗?

    嗯,这是饮鸩止渴的做法,修改SubjectImpl源代码有几个不妥的地方:①不一定所有的sub.request()方法都需要检查时间;②有的源码包不是你想改就能改的;

    代理设计模式为我们提供了方案:设计一个代理类SubjectProxy,其内部持有一个SubjectImpl的引用,相当于在SubjectImpl外面做了一个包装。Client不直接操作SubjectImpl,而是操作代理类SubjectProxy的对象,在其内部转发请求之前和之后都可以插入一些额外的操作。

     1 public class SubjectProxy implements ISubject{
     2  private ISubject proxied;  
     3  public void bind(ISubject sub){
     4    this.proxied = sub;
     5  }
     6      
     7  public void request(){  //重写接口的request方法
     8    Date start = new Date(DateUtil.timeOfToday(0, 0, 0));
     9    Date end = new Date(DateUtil.timeOfToday(5, 59, 59));
    10    Date now = new Date();
    11    if(now.after(start)&&now.before(end)){
    12      System.out.println("系统维护时间,禁止请求...");
    13      return;    //不会执行被代理对象的实际方法
    14    }
    15 
    16    proxied.request();    //转发请求
    17   }
    18 }

     用户持有并操作代理类对象:

    1 static public void main(String[] args){
    2     ISubject proxy = new SubjectProxy();   //new一个代理对象,并向上转型
    3     proxy.bind(new SubjectImpl());  //将一个SubjectImpl对象绑定到代理对象上
    4     //用户通过代理对象来访问具体的SubjectImpl资源
    5     proxy.request();
    6 }

    这样在用户调用proxy.request()方法的时候,首先会执行SubjectProxy类中的request方法,此方法在实际调用SubjectImpl的request方法之前会作时间判断。

    上面的这种代理模式称为是静态代理模式。其特点是,需要为每一个接口都对应的设计一个代理类。这样,当有成百上千个接口的时候,就对应着有成百上千个代理类!!!

    与之相对应的是动态代理。后面继续分析...

    参考:《Spring揭秘》

  • 相关阅读:
    Gogh-位图编纂次序
    Skype 1.4 for Linux 掉掉更新
    Jokosher 0.9
    [推荐]实用网址大全
    创建异形窗口[2]
    创建异形窗口[3]
    动态列表
    给系统菜单添加菜单项
    演示控件的 Anchors 属性
    使用 WM_NCHITTEST 消息判断鼠标所在窗口的部位
  • 原文地址:https://www.cnblogs.com/lj95801/p/5392529.html
Copyright © 2020-2023  润新知