善用設計模式-代理模式

一、爲什麼要用代理模式

        1).安全考慮:可以屏蔽客戶端直接訪問真實對象;

        2).延遲對真實對象的加載,提升系統啓動時間;

        3).在代理類中可進行類似AOP編程

二、實用場景(轉)

       1) 遠程代理(Remote  Proxy)爲一個位於不同的地址空間的對象提供一個本地的代理對象。如果讓你直接coding去調用,你需要處理網絡連接、處理打包、解包等等非常複雜的步驟,所以爲了簡化客戶端的處理,我們使用代理模式,在客戶端建立一個遠程對象的代理,客戶端就象調用本地對象一樣調用該代理,再由代理去跟實際對象聯繫,對於客戶端來說可能根本沒有感覺到調用的東西在網絡另外一端,這實際上就是Web Service的工作原理。
       2) 虛擬代理(Virtual Proxy)如果需要創建一個資源消耗較大的對象,先創建一個消耗相對較小的對象來表示,真實對象只在需要時纔會被真正創建。 
       3) 保護代理(Protection Proxy)控制對原始對象的訪問。保護代理用於對象應該有不同的訪問權限的時候。
       4) 智能指引(Smart Reference)取代了簡單的指針,它在訪問對象時執行一些附加操作。
       5) Copy-on-Write代理:它是虛擬代理的一種,把複製(克隆)操作延遲到只有在客戶端真正需要時才執行。一般來說,對象的深克隆是一個開銷較大的操作,Copy-on-Write代理可以讓這個操作延遲,只有對象被用到的時候才被克隆。

三、代理模式涉及角色

      1) 代理主題接口

      2) 真實主題類

      3) 代理類

      4) 調用端

四、具體實現方法

      1) 靜態代理

       

/**
 * @author pengl
 * 2014-5-3
 * 描述:代理模式的主題接口
 */
public interface IDBQuery {
	public String query();
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:真實主題類
 */
public class DBQuery implements IDBQuery {
	public String query() {
		return "query strings";
	}
	
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:代理類
 */
public class DBQueryProxy implements IDBQuery{
	private DBQuery dbQuery = null;
	public String query() {
		if(dbQuery==null){
			dbQuery = new DBQuery();
		}
		return dbQuery.query();
	}
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:客戶端調用
 */
public class Main {
	public static void main(String[] args) {
		IDBQuery query = new DBQueryProxy();
		query.query();
	}
}

      2) 動態代理

/**
 * @author pengl
 * 2014-5-3
 * 描述:代理模式的主題接口
 */
public interface IDBQuery {
	public String query();
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:真實主題類
 */
public class DBQuery implements IDBQuery {	
	public String query() {
		return "query strings";
	}
	
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:代理類[java動態代理]
 */
public class DynamicProxyFactory implements InvocationHandler{
	private Object object;
	public DynamicProxyFactory(Object obj){
		this.object = obj;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		/**
		 * 我們可以在這個封裝的動態代理類裏添加日誌等操作
		 */
		Logger.getLogger(this.getClass()).warn("開始調用動態代理類");
		method.invoke(object, args);
		Logger.getLogger(this.getClass()).warn("調用動態代理類結束");
		return null;
	}
}

/**
 * @author pengl
 * 2014-5-3
 * 描述:客戶端調用
 */
public class Main {
	public static void main(String[] args) {
		IDBQuery query = new DBQuery(); //被代理類
		InvocationHandler ih = new DynamicProxyFactory(query); //初始化代理類
		IDBQuery proQuery = (IDBQuery) Proxy.newProxyInstance(query.getClass().getClassLoader(), query.getClass().getInterfaces(), ih);
		proQuery.query();
	}
}


          上面演示的只是JDK自帶的動態代理,還有CGLIB、Javassist、ASM等實現庫。如Hibernate框架中的load查詢,就是使用的CGLIB實現庫。


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