首页 > 代码库 > 设计模式之代理模式
设计模式之代理模式
代理模式就是为另一个对象提供一个替身,来控制对这个对象的访问。
一开始觉得代理没有有什么作用,觉得代理也只是调用了真实对象的方法,后来才知道,代理的用处还是挺大的。
比如说,代理可以控制不同人对于同一个对象的访问,控制他们使用的权限,称为保护代理。代理还可以作为另一个JVM上对象的本地代表,客户端需要请求数据的时候,由代理利用网络转发到远程执行,并且结果会通过网络返回给代理,由代理将结果返回给用户,称为远程代理。当访问的对象需要很大的开销,这时候代理可以作为其代表,到了需要对象的时候才创建它,称为虚拟代理,例如浏览网页时,通常加载图片需要很长的时间,在未加载完成前,代理可以先显示“加载中”或者默认的图片,等到加载完成了,代理显示真正的图片。
代理模式的类图如下:
Java在java.lang.reflect包中有自己的代理支持,实际的代理类是在运行时创建的,所以称为动态代理,动态代理的类图和普通的代理类图不一样。
现在我们利用java提供的代理类,来实现对对象访问的控制。
假设有一个约会网站,每个人可以对自己的信息修改,但不能设置自己的评分,其他人可以设置评分,但不能修改信息。
类图如下:
PersonBean接口,就是RealSubject和Proxy都实现的接口
public interface PersonBean{ public String getName(); public String getGender(); public int getHotOrNotRate(); public void setName(String name); public void setGender(String gender); public void setHotOrNotRate(int rate);}
PersonBeanImpl类,就是real subject类
public class PersonBeanImpl implements PersonBean{ private String name; private String gender; private int rate; public String getName() { return name; } public String getGender() { return gender; } public int getHotOrNotRate() { return rate; } public void setName(String name) { this.name=name; } public void setGender(String gender) { this.gender=gender; } public void setHotOrNotRate(int rate) { this.rate=rate; } }
控制本人操作的OwnerInvocationHandler
import java.lang.reflect.*;public class OwnerInvocationHandler implements InvocationHandler{ PersonBean person; public OwnerInvocationHandler(PersonBean person) { this.person=person; } public Object invoke(Object proxy,Method method,Object[] args)throws Exception { if(method.getName().startsWith("get"))//如果调用的是get方法 { return method.invoke(person,args);//直接调用方法 } else if(method.getName().startsWith("set"))//如果调用的是set方法 { if(method.getName().equals("setHotOrNotRate"))//如果调用的是设置评分的方法 { throw new IllegalAccessException();//抛出异常 } else { return method.invoke(person,args);//直接调用 } } return null; } }
控制非本人操作的NotOwnerInvocationHandler
public class NoOwnerInvocationHandler implements InvocationHandler{ PersonBean person; public NoOwnerInvocationHandler(PersonBean person) { this.person=person; } public Object invoke(Object proxy,Method method,Object[] args) throws Exception { if(method.getName().startsWith("get"))//如果调用的是get方法 { return method.invoke(person,args);//直接调用方法 } else if(method.getName().startsWith("set"))//如果调用的是set方法 { if(method.getName().equals("setHotOrNotRate"))//如果调用的是设置评分的方法 { return method.invoke(person,args);//直接调用 } else { throw new IllegalAccessException();//抛出异常 } } return null; } }
负责产生Proxy对象的工厂
public class HandlerFactory{ public static PersonBean getOwnerProxy(PersonBean person) { return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new OwnerInvocationHandler(person)); } public static PersonBean getNoOwnerProxy(PersonBean person) { return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new NoOwnerInvocationHandler(person)); } }
测试类
public class Test{ public static void main(String[] args) { PersonBean judy=getPersonFromDatabase("judy"); PersonBean ownProxy=HandlerFactory.getOwnerProxy(judy); System.out.println("name:"+ownProxy.getName()); System.out.println("gender:"+ownProxy.getGender()); System.out.println("Rate:"+ownProxy.getHotOrNotRate()); try { ownProxy.setHotOrNotRate(10000); } catch(Exception e) { System.out.println("You can‘t set your own rate!"); } PersonBean noOwnProxy=HandlerFactory.getNoOwnerProxy(judy); System.out.println("I am Jenny.I am dating Judy."); System.out.println("name:"+noOwnProxy.getName()); System.out.println("gender:"+noOwnProxy.getGender()); System.out.println("Rate:"+noOwnProxy.getHotOrNotRate()); System.out.println("change Judy‘s rate to 90"); noOwnProxy.setHotOrNotRate(90); System.out.println("Now Judy‘s Rate:"+noOwnProxy.getHotOrNotRate()); try { noOwnProxy.setName("ChenHaiqing"); } catch(Exception e) { System.out.println("You have no access to change her infomation."); } } /** 模拟从数据库中提取数据 **/ public static PersonBean getPersonFromDatabase(String name) { PersonBean person=new PersonBeanImpl(); person.setName(name); person.setGender("male"); person.setHotOrNotRate(100); return person; } }
运行结果:
可以看到,当Judy尝试改变自己的评分时,就会出现“You can‘t set your own rate!”,当Jenny尝试改变Judy的个人信息时,就会出现"No access!"
代理模式控制了对象的访问,但是proxy类到底是什么时候生成的呢?可以看看工厂里的代码。
public static PersonBean getOwnerProxy(PersonBean person) { return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),person.getClass().getInterfaces(),new OwnerInvocationHandler(person)); }
调用了Proxy的静态方法,相当于生成了Proxy类并返回其对象,而且把它和InvocationHandler联系在一起。
当客户端调用proxy.getName()方法时,proxy会接着调用InvocationHandler的invoke方法,由它来决定如何处置这一请求,可以转发给RealSubject,遇到没有权限的操作则抛出异常。
代理模式应用范围很广,请看下图:
设计模式之代理模式