设计模式__代理模式

代理设计模式

给某一个对象提供代理对象,由代理对象控制具体对象的使用。

 

什么叫代理?

在生活中,代理无处不在,如各种代理商。

如:生产电脑的厂家不会直接把电脑卖给零售客户,而是通过代理来完成销售。客户也不用因为买电脑而跑去厂家。

这就是代理过程

 

        代理类:

        主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

        代理类本身并不真正实现服务,而是通过调用委托类的相关方法,来提供特定的服务。 

        代理类与委托类都实现了同一个接口。

 

 

代理中涉及的角色:

1,抽象主题角色:声明真实角色和代理对象的共同接口

2,真实角色:是我们最终要引用的对象

3,代理角色:代理对象内部加了一些自己的处理方法,最后还是要去调用真实角色的处理方法。

 

简单代理结构图:

 

 

为什么要使用代理?

1,授权机制不同,不用级别的用户对同一对象拥有不同的访问权限。如论坛中,注册用户和游客的权限差别。

2,不让客户端直接操作到某个对象,但又必须和那个对象有所互动。

如:

在网络中,在我们访问某个远端的服务器上的某个对象的时候,如果直接操作这个对象,网络速度原因可能比较慢,那我们就可以先用Proxy来代替那个对象。

如果我们在加载示一个很大的图片的时候,可以让其在后台加载,代理中显示等待信息。

 

下面看实例:

package proxy;

//公共接口,产生须要让其子类实现的方法
interface SellInterface
{
	public void  sell();
}

//真实角色,实现SellInterface
class SellFactory implements SellInterface
{
	public void sell() {
		System.out.println("真实角色在处理问题");
	}
}

//代理类
class MyProxy implements SellInterface
{
	SellFactory sf;  //代理类须要调用真实角色的处理方法
	public void sell()
	{
		/*
		     这样调用,可以让这个代理类在这里先处理一些问题,
		     比如判断什么的,如果不满足,就不用去调用具体实现方法了,这样可以提高效率。
		     在实际应用中,如我们在访问网站时,也是先访问的本地服务器,如果有自己所须要的,
		     在本地就可以完成访问,没必要每次都去总部访问资源,这样很占空间。
		     再比如:我们买正品戴尔电脑,不用去总部,在代理处就可以了。如果代理处满足不了,
		     在去总部。
		*/
		if(test()){  //满足条件
			sf = new SellFactory();
			sf.sell();
		}
		else
			throw new RuntimeException();			
	}
	
	protected boolean test()
	{
		return true;
	}
}
//客户端
public class CommonProxy {
	public static void main(String [] args)
	{
		//在代理处办事
		SellInterface mp = new MyProxy();
		mp.sell();
	}
}

 

代理模式的--动态代理 

 JVM在执行时,运用反射机制动态创建一个类,如果这个类是代理类,那么这样的形式就是动态代理类。 

 

动态代理和普通代理的区别?

  普通代理类:在程序运行前,代理类的class文件已经存了

  动态代理类:程序运行时 运用反射机制 动态创建而成

 

 在上面的代理中,我们让代理类实现了接口SellInterface,这样使得代码,通用性很低。

 在java中提供了其它方法,使得代理类通用性提高了。

 

 通过类Proxy  和 接口InvocationHandler 来实现对代理模式的支持。

 

 Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

 

代理创建过程

 1,首先通过Proxy类的方法来创建代理对象,须要通过来主题角色建立

 2,代理类须要实现InvocationHandler 接口

 

动态代理结构图

 

 

 

 动态代理的建立:两种方法

由Proxy类 和 接口 InvocationHandler 来共同完成。

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。

InvocationHandler 是代理实例的调用处理程序实现的接口.

 

如:建立List list = new ArrayList 集合的代理类

a , 通过获取构造方法来建立

   // 1,获取动态代理类的Class
		Class clazz = Proxy.getProxyClass(
				List.class.getClassLoader(),   // 目标类所实现的接口的类加载器
				new Class[]{List.class}  //目标类所实现的接口
				);

  // 2, 实现InvocationHandler接口,通过这个去调用目标类。
		InvocationHandler ih = new InvocationHandler(){
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				//可以加入功能
				Object re = method.invoke(list, args);  //调用所要代理的对象的方法
				//可以加入功能
				return re;
			}
		};
 
  // 3,获取代理类的构造函数
		Constructor constructor = clazz.getConstructor(InvocationHandler.class);
		
  // 4,创建代理对象
		List myproxy = (List)constructor.newInstance(ih);

b , 直接通过newProxyInstance 来建立
	List myproxy2 = (List)Proxy.newProxyInstance(
				List.class.getClassLoader(),   // 目标类所实现的接口的类加载器
				new Class[]{List.class},  //目标类所实现的接口
				new InvocationHandler(){  // 实现接口,去调用目标类
					public Object invoke(Object proxy, Method method,Object[] args) throws Throwable {
						//可以加入功能
						Object re = method.invoke(list, args);  //调用所要代理的对象的方法
						//可以加入功能
						return re;
					}
				}
			);


 

示例代码:

ackage proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Collection;

interface SellInterface
{
	public void  sell();
}

class SellFactory implements SellInterface
{
	public void sell() {
		System.out.println("真实角色在处理问题");
	}
}

//代理类1,尽量面向对向,使代理类更通用。
class MyProxy implements InvocationHandler
{
	static Object obj;
	MyProxy(Object obj)  // obj:传入须要代理的类
	{
		this.obj = obj;
	}
	 //通过Proxy类的newProxyInstance方法来返回代理对象 
	public static Object factory(Object o) 
	{
		Class clazz = o.getClass();
		return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new MyProxy(o));
	}
	/*
	 * 	实现InvocationHander接口的invoke
	 * 	proxy:代理实例
	 * 	method:对应于在代理实例上调用的接口方法的 Method 实例
	 * 	args [] :传入代理实例上方法的参数值的对象数组.
	*/
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		System.out.println("函数调用前被拦截了"+method);
	//	System.out.println(proxy.getClass().getName());
		
		//代理调用真实角色处理方法
		Object mo = method.invoke(obj, args);
		
		System.out.println("函数调用后进行处理"+method);
		
		return mo;
	}
}

//客户端
public class DynamicProxy {
	public static void main(String [] args) throws Exception
	{	
		SellInterface mp = (SellInterface)MyProxy.factory(new SellFactory());
		mp.sell();
			
//		test();
	}
	public static void test() throws Exception
	{
		//获取代理类Proxy的字节码
		System.out.println("-------------constructors   list-------------");
		Class clazzProxy = Proxy.getProxyClass(Object.class.getClassLoader(), Collection.class);
		System.out.println(clazzProxy.getName());
		
		//获取代理类Proxy的构造方法
		Constructor [] constructors = clazzProxy.getConstructors();
		
		//获取Proxy的方法
		System.out.println("-------------method   list----------------");
		Method [] methods = clazzProxy.getDeclaredMethods();
		for(Method m : methods)
		{
			//以()形式输出方法里的参数
			StringBuilder sb = new StringBuilder();
			sb.append(m.getName());
			sb.append("(");
		
			//列出方法的参数
			Class [] clazzParam = m.getParameterTypes();
			for(Class c : clazzParam)
			{
				sb.append(c.getName()+",");
			}
			if(clazzParam!=null && clazzParam.length!=0)
				sb.deleteCharAt(sb.length()-1);
			sb.append(")");
			System.out.println(sb);
		}
		
		//创建代理对象的方法
		System.out.println("--------------create    instance  -------------------");
		//创建构造器
		Constructor constructor = clazzProxy.getConstructor(InvocationHandler.class);
		
		//方法一:
		class MyInvocationHandler implements InvocationHandler{
			public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {
				System.out.println("方法一");
//				Object retVal = method.invoke(obj, args); 
				return null;
			}
		}
		Object proxy1 = constructor.newInstance(new MyInvocationHandler());
		System.out.println(proxy1);
		
		//方法二
		Object proxy2 = constructor.newInstance(new InvocationHandler(){
			public Object invoke(Object proxy, Method method, Object[] args)  throws Throwable {
				System.out.println("方法二");
//				Object retVal = method.invoke(obj, args); 
				return null;
			}
			
		});
		System.out.println(proxy2);
		
		//方法三:
		Object proxy3 = Proxy.newProxyInstance(
				Object.class.getClassLoader(),
				new Class[]{Collection.class},
				new InvocationHandler(){	
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 								{			
						System.out.println("开始切面。。。"+method);
				//		Object retVal = method.invoke(obj, args); //动态调用真实角色处理方法
						System.out.println("结束切面。。。"+method);
						return null;
						}
					}
				);
		System.out.println(proxy3);
	}
}

 

用代理实现AOP拦截机制的例子

可以拦截我们指定的函数,并在拦截前后根据需要进行处理.

除了拦截,代理模式还常用于资源加载,当我们要加载的资源很大时,我们可以让真实主题角色在后台加载资源,让代理主题角色负责处理前台的等待提示信息

 

看下面代码示例:

package proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.util.Collection;

interface AopInterface
{
	public void  start(Object obj); //切面--调用前的处理 
	public void end(Object obj); //切面--调用后处理 
}

class AopInterfaceImp implements AopInterface  //对象切面的具体操作
{
	public void start(Object obj) {
		System.out.println("调用前被拦截了,做一些其它的事");
	}

	public void end(Object obj) {
		System.out.println("调用后被拦截,去处理一些其它事");	
	}
}

//代理类
class MyProxy4 implements InvocationHandler
{
	private AopInterface aop; //切入时调用
	private Object obj;
	private String methodName = null;  //要拦截的方法名字
	
	MyProxy4() {} // obj:传入须要代理的类
		
	//通过Proxy类的newProxyInstance方法来返回代理对象 
	public  Object factory(Object o) 
	{
		this.obj = o;
		Class clazz = o.getClass();
		return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
	}

	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		
		//在这里还应该做一些判断,如:aop没有初始化。
		
		Object mo;
		
		//如果该方法是要拦截的
		if(methodName != null && method.toString().indexOf(methodName)!=-1) //这里为什么是用indexOf呢?
						 											//因为method.toString() 返回的是
														// public abstract void proxy.TestInterface.add() 形式。
		{
			aop.start(obj); 
		
			//代理调用真实角色处理方法
			mo = method.invoke(obj, args);
		
			aop.end(obj);
		}
		else
		{
			mo = method.invoke(obj, args);
		}
			
		return mo;
	}

	public AopInterface getAop()
	{	return aop; 	}
	
	public void setAop(AopInterface aop)
	{	this.aop = aop; }
	
	public String setMethodName(String methodName)
	{
		return this.methodName = methodName;
	}
	
}

//用于测试的
interface TestInterface {  
    public void add();  
    public void dele();  
}  
  
class ImpTest implements TestInterface{  
  
    public void add() {  
        System.out.println("........... add()");  
    }  
  
    public void dele(){  
        System.out.println("............ acc()");  
    }  
  
}  

//客户端
public class DynamicProxy2 {
	public static void main(String [] args) throws Exception
	{	
		MyProxy4 mp = new MyProxy4();	//建立代理对象
		
		mp.setAop(new AopInterfaceImp()); 	//给代理设置所要代理的类
		
		mp.setMethodName("add"); //设置须要被拦截的方法名
		
		//通过代理建立测试类对象 ,因为要让测试类在执行时,先去代理处
		TestInterface ai = (TestInterface)mp.factory(new ImpTest());
		
		ai.add();	//执行要拦截的add()方法
		
		ai.dele();	//执行没有被拦截的dele()方法

	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值