在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。
在软件设计中,使用代理模式的例子也很多,例如,要访问的远程对象比较大(如视频或大图像等),其下载要花很多时间。还有因为安全原因需要屏蔽客户端直接访问真实对象,如某单位的内部数据库等。
代理模式的定义与特点
代理模式的定义:由于某些原因需要给某对象提供一个代理以控制对该对象的访问。这时,访问对象不适合或者不能直接引用目标对象,代理对象作为访问对象和目标对象之间的中介。
代理模式的主要优点有:
- 代理模式在客户端与目标对象之间起到一个中介作用和保护目标对象的作用;
- 代理对象可以扩展目标对象的功能;
- 代理模式能将客户端与目标对象分离,在一定程度上降低了系统的耦合度;
其主要缺点是:
- 在客户端和目标对象之间增加一个代理对象,会造成请求处理速度变慢(学过Java web的同学,应知道tomcat,就类似于这个,拦截请求来转发);
- 增加了系统的复杂度;
代理模式的结构与实现
代理模式的结构比较简单,主要是通过定义一个继承抽象主题的代理来包含真实主题,从而实现对真实主题的访问,下面来分析其基本结构和实现方法。
1. 模式的结构
代理模式的主要角色如下。
- 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
- 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
- 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。
2. 模式的实现
(1)抽象主题
//抽象主题
interface Subject
{
void Request();
}
(2)具体主题
//真实主题
class RealSubject implements Subject
{
public void Request()
{
System.out.println("访问真实主题方法...");
}
}
(3)代理类
//代理
class Proxy implements Subject
{
private RealSubject realSubject;
public void Request()
{
if (realSubject==null)
{
realSubject=new RealSubject();
}
preRequest();
realSubject.Request();
postRequest();
}
public void preRequest()
{
System.out.println("访问真实主题之前的预处理。");
}
public void postRequest()
{
System.out.println("访问真实主题之后的后续处理。");
}
}
(4)测试类
public class ProxyTest
{
public static void main(String[] args)
{
Proxy proxy=new Proxy();
proxy.Request();
}
}
如果真实主题增加,代理类也需要增加(当然你也可以通过多态,代理类持有抽象主题类,只需要传一个真实主题类参数,就可以解决这个问题。只不过每一个抽象类,我们需要增加一个代理类),设计代理以前真实主题必须事先存在,不太灵活。这也被成为静态代理模式(在程序员运行之前,代理类.class文件就已经被创建了)。
下面我将给大家介绍下动态代理模式
所谓动态代理,是指在程序运行才会常见一个代理对象
动态代理的组成:
1.需要被代理的抽象类
2.需要被代理的具体类
public interface Animal {
public void action();
public void breath();
}
//被代理类Cat
public class Cat implements Animal {
@Override
public void action() {
System.out.println("喵喵喵~~~~");
}
@Override
public void breath() {
System.out.println("猫式呼吸法~~~~");
}
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MyProxy implements InvocationHandler {
Object obj;
public void setObj(Object obj){
this.obj = obj;
}
//method:代理对象执行的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("==============代理类开始执行!!!!=============");
//returnVal是方法的返回值
Object returnVal = method.invoke(obj, args);
System.out.println("==============代理类执行结束!!!!=============");
return returnVal;
}
}
代理对象工具类
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static Object getProxyInstance(Object obj) {
MyProxy proxy = new MyProxy();
proxy.setObj(obj);
/*
* obj.getClass().getClassLoader():被代理对象的类加载器
* obj.getClass().getInterfaces() :被代理对象的接口
* 实质上是通过反射将被代理类的加载器和接口与代理对象关联起来
* obj :是被代理的对象
* proxy:实现InvocationHandler的接口
*/
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), proxy);
}
}
测试类
import java.lang.reflect.Proxy;
public class TestDynamicProxy {
public static void main(String[] args) {
Cat cat = new Cat();
Object proxyInstance = ProxyUtil.getProxyInstance(cat);
Animal animal = (Animal) proxyInstance;
animal.action();
animal.breath();
}
}