1.1概述
为其他对象提供一种代理以控制对这个对象的访问。这就是代理模式的定义。
当用户希望和某个对象打交道,但程序可能不希望用户直接访问该对象,而是提供一个特殊的对象,这个特殊的对象被称作当前用户要访问对象的代理,程序让用户和对象的代理打交道,即让用户通过访问代理来访问想要访问的对象。在代理模式中,代理的特点是:它与所代理的对象实现了相同的接口,也就是说代理和它多代理的对象向用户公开了相同的方法,当用户请求代理调用该方法时,代理可能需要验证某些信息或检查它所代理的对象是否可用,当代理确认它所代理的对象能调用箱通风的方法时,就把实际的方法调用委派给它所代理的对象,即让所代理的对象调用同样的方法。
例如,公司里的秘书是老板的代理,老板和秘书都有听电话的方法:herePhone()。公司要求用户必须首先和秘书通电话才能和老板通电话,也就是说,用户必须首先请求秘书调用herePhone(),当秘书确认老板可以接电话时,就将用户的实际请求委派给老板,即让老板调用herePhone()方法。具体类关系如下图一所示:
图一:老板和秘书
1.2模式的结构
代理模式包括以下三种角色:
(1)抽象主题(Subject):抽象主题是一个接口,该接口是对象和它的代理所共用的接口,即是RealSubject角色和Proxy角色实例所实现的接口。
(2)实际主题(RealSubject):实际主题是实现抽象主题接口的类。实际主题的实例是代理角色(Proxy)实例所要代理的对象。
(3)代理(Proxy):代理是实现抽象主题接口的类(代理和实际主题实现了相同的接口)。代理含有主题接口声明的变量,该变量用来存放RealSubject角色的实例引用,这样一来,代理的实例就可以控制对它所包含的RealSubject角色的实例访问,即可以控制对它所代理对象的访问。
代理模式结构的类图如下图二所示:
图二:代理模式的类图
1.3代理模式的优点
(1)代理模式可以屏蔽用户真正请求的对象,使用户程序和真正的对象之间解耦。
(2)使用代理来担当那些创建耗时的对象的替身。
1.4适合使用代理模式的情景
(1)程序可能不希望用户直接访问该对象,而是提供一个特殊的对象以控制对当前对象的访问。
(2)如果一个对象(例如很大的图像)需要很长时间才能加载完成。
(3)如果对象位于远程主机上,需要为用户提供访问该远程对象的能力。
1.5代理模式的使用
以下通过一个简单的问题来描述怎样使用代理模式,这个简单的问题是:用户输入三个代表三角形三边长度的数值,代理对象验证用户输入的三个数值是否能构成三角形,如果能构成三角形,就创建一个三角形对象,并让该三角形对象计算自身的面积。
首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图所示:
(1)抽象主题(Subject)
本问题中,抽象主题角色是Geometry接口,Geometry接口的代码如下:
package com.liuzhen.nineteen_proxy; public interface Geometry { public double getArea(); }
(2)实际主题(RealSubject)
对于本问题,实际主题(RealSubject)是Triangle类,代码如下:
package com.liuzhen.nineteen_proxy; public class Triangle implements Geometry { double sideA, sideB, sideC, area; public Triangle(double a,double b,double c){ sideA = a; sideB = b; sideC = c; } public double getArea() { double p = (sideA+sideB+sideC)/2.0; area = Math.sqrt(p*(p-sideA)*(p-sideB)*(p-sideC)); return area; } }
(3)代理(Proxy)
对于本问题,代理是TriangleProxy类,代码如下:
package com.liuzhen.nineteen_proxy; public class TriangleProxy implements Geometry { double sideA, sideB, sideC; Triangle triangle; public void setABC(double a,double b,double c){ sideA = a; sideB = b; sideC = c; } public double getArea() { if(sideA+sideB > sideC && sideA+sideC > sideB && sideB+sideC > sideA){ triangle = new Triangle(sideA,sideB,sideC); double area = triangle.getArea(); //让所代理的对象调用getArea()方法 return area; } else return -1; } }
(4)具体使用
通过NineteenApplication类来具体实现上述相关类和接口,来实现代理模式的运用,其代码如下:
package com.liuzhen.nineteen_proxy; import java.util.Scanner; public class NineApplication { public static void main(String[] args){ Scanner reader = new Scanner(System.in); System.out.println("请输入三个数,每输入一个数按回车确认:"); double a, b , c; a = reader.nextDouble(); b = reader.nextDouble(); c = reader.nextDouble(); TriangleProxy proxy = new TriangleProxy(); proxy.setABC(a, b, c); double area = proxy.getArea(); System.out.println("面积是:"+area); } }
运行结果:
请输入三个数,每输入一个数按回车确认: 20 20 20 面积是:173.20508075688772
参考资料:
1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5