設計模式__代理模式

代理設計模式

給某一個對象提供代理對象,由代理對象控制具體對象的使用。

 

什麼叫代理?

在生活中,代理無處不在,如各種代理商。

如:生產電腦的廠家不會直接把電腦賣給零售客戶,而是通過代理來完成銷售。客戶也不用因爲買電腦而跑去廠家。

這就是代理過程

 

        代理類:

        主要負責爲委託類預處理消息、過濾消息、把消息轉發給委託類,以及事後處理消息等。

        代理類本身並不真正實現服務,而是通過調用委託類的相關方法,來提供特定的服務。 

        代理類與委託類都實現了同一個接口。

 

 

代理中涉及的角色:

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()方法

	}
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章