设计模式之代理模式

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

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

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

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

 

posted on 2015-02-04 11:01  qingfei  阅读(172)  评论(0编辑  收藏  举报