一、代理模式

代理模式是Java常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
为什么要采用这种间接的形式来调用对象呢?一般是因为客户端不想直接访问实际的对象,或者访问实际的对象存在困难,因此通过一个代理对象来完成间接的访问。

  • 代理对象:起到中介作用,连接客户端和目标对象
  • 例子:电脑桌面的快捷方式。电脑对某个程序提供一个快捷方式(代理对象),快捷方式连接客户端和程序,客户端通过操作快捷方式就可以操作那个程序

代理模式UML图:

aHR0cHM6Ly9pbWFnZXMuY25ibG9ncy5jb20vY25ibG9nc19jb20vbWFjaGluZS80NDY5ODAvb19wcm94eS1wYXR0ZXJuLWNsLnBuZw.jpg

 代理模式角色分为 4 种:

  1. 主题接口(Subject):定义代理类和真实主题的公共对外方法,也是代理类代理真实主题的方法;
  2. 真实主题(RealSubject):真正实现业务逻辑的类;
  3. 代理类(ProxySubject):用来代理和封装真实主题;
  4. 客户端(Client):使用代理类和主题接口完成一些工作

代理模式可以有两种实现的方式,一种是静态代理类,另一种是动态代理。下面我们主要讲解静态代理

二、静态代理实现

我们先看针对上面关于快捷方式的例子,再看静态代理的特点。

客户端操作快捷方式,快捷方式(代理对象) 代替 应用程序(真实对象) 去打开运行程序(间接访问的操作)

创建抽象对象接口(Subject):声明程序(真实对象)需要让快捷方式(代理对象)帮忙做的事(打开程序)

public interface Subject {
    void open();
}

创建真实对象类(RealSubject),即应用程序

public class RealSubject implement Subject{
    @Override
    public void open() {  
        System.out.println(”打开QQ“);  
    }  
}

创建代理对象类(Proxy),即”QQ快捷方式“,并通过代理类创建真实对象实例并访问其方法

public class Proxy  implements Subject{
    @Override
    public void open() {
      //引用并创建真实对象实例,即”QQ“
      RealSubject qq = new RealSubject();
      //调用真实对象的方法,进行快捷方式打开
      qq.open();
 
      //代理对象额外做的操作
      public void others(){
      System.out.println(”我是QQ的快捷方式“);  
    }
    }
}

客户端调用

public class ProxyPattern {
 
    public static void main(String[] args){
 
    Subject QQproxy = new Proxy();
    proxy.open();
    }
}

结果输出:
    打开QQ
    我是QQ的快捷方式

优点:

  • 协调调用者和被调用者,降低了系统的耦合度
  • 代理对象作为客户端和目标对象之间的中介,起到了保护目标对象的作用

缺点:

  • 由于在客户端和真实主题之间增加了代理对象,因此会造成请求的处理速度变慢;
  • 实现代理模式需要额外的工作(有些代理模式的实现非常复杂),从而增加了系统实现的复杂度。

代理模式应用场景

代理模式有多种应用场合,如下所述: 

  1. 远程代理,也就是为一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实。比如说 WebService,当我们在应用程序的项目中加入一个 Web 引用,引用一个 WebService,此时会在项目中声称一个 WebReference 的文件夹和一些文件,这个就是起代理作用的,这样可以让那个客户端程序调用代理解决远程访问的问题;
  2. 虚拟代理,是根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象。这样就可以达到性能的最优化,比如打开一个网页,这个网页里面包含了大量的文字和图片,但我们可以很快看到文字,但是图片却是一张一张地下载后才能看到,那些未打开的图片框,就是通过虚拟代里来替换了真实的图片,此时代理存储了真实图片的路径和尺寸;
  3. 安全代理,用来控制真实对象访问时的权限。一般用于对象应该有不同的访问权限的时候;
  4. 指针引用,是指当调用真实的对象时,代理处理另外一些事。比如计算真实对象的引用次数,这样当该对象没有引用时,可以自动释放它,或当第一次引用一个持久对象时,将它装入内存,或是在访问一个实际对象前,检查是否已经释放它,以确保其他对象不能改变它。这些都是通过代理在访问一个对象时附加一些内务处理;
  5. 延迟加载,用代理模式实现延迟加载的一个经典应用就在 Hibernate 框架里面。当 Hibernate 加载实体 bean 时,并不会一次性将数据库所有的数据都装载。默认情况下,它会采取延迟加载的机制,以提高系统的性能。Hibernate 中的延迟加载主要分为属性的延迟加载和关联表的延时加载两类。实现原理是使用代理拦截原有的 getter 方法,在真正使用对象数据时才去数据库或者其他第三方组件加载实际的数据,从而提升系统性能。

以上是最常用的使用场景,其他还包括:

  • 防火墙代理:保护目标不让恶意用户靠近
  • Cache代理:为结果提供临时的存储空间,以便其他客户端调用 

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,有关动态代理的博文可移步【设计模式】——代理模式(动态)


版权声明:文章转载请注明来源,如有侵权请联系博主删除!
最后修改:2019 年 12 月 25 日 01 : 50 PM
如果觉得我的文章对你有用,请随意赞赏
评论打卡也可以哦,您的鼓励是我最大的动力!