zoukankan      html  css  js  c++  java
  • 设计模式之代理模式

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

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

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

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

     

  • 相关阅读:
    渲染管线
    C++windows内核编程笔记day13 进程、线程与信号量
    稻盛和夫:真正的聪明人,善于把事物简单化
    学会把复杂问题简单化
    任何事物,只要抓住了规律,就等于牵住了牛鼻子
    菩萨奶奶引领我学佛
    数据库每分钟运行监控SQL
    MySQL 从库down机
    sql server 跟踪日志
    胡小林:把日常生活中碰到的事变成我们发露忏悔的机会
  • 原文地址:https://www.cnblogs.com/qingfei1994/p/4271848.html
Copyright © 2011-2022 走看看