首页 > 代码库 > 设计模式之代理模式

设计模式之代理模式

 代理模式就是为另一个对象提供一个替身,来控制对这个对象的访问。

 一开始觉得代理没有有什么作用,觉得代理也只是调用了真实对象的方法,后来才知道,代理的用处还是挺大的。

 比如说,代理可以控制不同人对于同一个对象的访问,控制他们使用的权限,称为保护代理。代理还可以作为另一个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,遇到没有权限的操作则抛出异常。

 代理模式应用范围很广,请看下图:

 技术分享

设计模式之代理模式