Java設計模式--代理模式【Proxy Pattern】

        什麼是代理模式呢?我們大家都知道微商,微商是代理供應商銷售產品的一方,簡單地說就是代替產品供應商賣產品。關於微商代理,首先我們從他們那裏買東西時通常不知道背後的供應商究竟是誰,也就是說,“目標對象”對我們來說是不可見的;其次,微商代理主要以朋友圈的人爲目標客戶,這就相當於爲供應商做了一次對客戶羣體的“過濾”。我們把微商代理MicroAgent和產品供應商ProductSupplier進一步抽象,前者可抽象爲代理類,後者可抽象爲委託類(被代理類)。

  代理(Proxy)設計模式的定義:爲其他對象提供一種代理以控制對這個對象的訪問,即通過代理對象訪問目標對象。這樣做的好處是既可以隱藏委託類的實現,又可以實現客戶與委託類間的解耦,在不修改委託類代碼的情況下能夠做一些額外的處理。

  

     Java中,代理模式分爲靜態代理和動態代理兩種方式。

  1、靜態代理

  若代理類在程序運行前就已經存在,那麼這種代理方式被成爲靜態代理,這種情況下的代理類通常都是我們在Java代碼中已經定義的,通常情況下, 靜態代理中的代理類和委託類會實現同一接口或是派生自相同的父類。

  下面我們用ProductSupplier類代表產品供應商,MicroAgent類代表微商代理,來介紹下靜態代理的簡單實現。    

package com.pattern.proxy.v1;
/**
 * 供應商總接口:定義了銷售產品的抽象方法
 * @author 
 *
 */
public interface Supplier {
   public void sellProduct();
}
package com.pattern.proxy.v1;
/**
 * 具體的產品供應商:實現了銷售產品的方式方法
 * @author 
 *
 */
public class ProductSupplier implements Supplier{
	@Override
	public void sellProduct() {//這纔是真的銷售產品
		System.out.println("ProductSupplier sell product...");
	}
}
package com.pattern.proxy.v1;
/**
 * 微商代理--只有自己清楚,我不是真正的供應商,只是負責代理銷售產品
 * @author 
 *
 */
public class MicroAgent implements Supplier{
	private Supplier supplier;//代理類持有一個委託類對象引用
	
	public MicroAgent() {//默認銷售X供應商的產品
		this.supplier = new ProductSupplier();
	}
	public MicroAgent(Supplier supplier) {//也可以銷售其他供應商的產品
		this.supplier = supplier;
	}
	
	@Override
	public void sellProduct() {//每天發朋友圈說我這裏有產品,你們來買吧
		this.supplier.sellProduct();//實際上是走的通道業務,需要找上級供應商拿貨銷售
	}
}
客戶端測試類:

package com.pattern.proxy.v1;
/**
 * 客戶端測試類
 * @author 
 *
 */
public class ClientTest {
   public static void main(String[] args){
	   //顧客看到微商代理的朋友圈,然後說我要買你的產品,
	   //然後微商拿貨賣給了顧客,顧客以爲產品是微商自己的
	   Supplier agent=new MicroAgent();
	   agent.sellProduct();
   }
}
    從MicroAgent類的定義我們可以看到,靜態代理可以通過聚合來實現,讓代理類持有一個委託類的引用即可。
2、動態代理

  什麼是動態代理?代理類在程序運行時創建的代理方式被成爲動態代理。 也就是說,這種情況下,代理類並不是在Java代碼中定義的,而是在運行時根據我們在Java代碼中的“指示”動態生成的。相比於靜態代理, 動態代理的優勢在於可以很方便的對代理類的函數進行統一的處理,而不用修改每個代理類的函數。 這麼說比較抽象,下面我們結合一個實例來介紹一下動態代理的這個優勢是怎麼體現的。
  現在,假設我們要實現這樣一個需求:在執行目標對象的銷售產品方法之前需要申請銷售額度,在銷售完畢後需要及時記錄銷售額度。我們還是以上面例子中的ProductSupplier類作爲委託類,MicroAgent類作爲代理類來進行介紹。如果使用靜態代理來實現這一需求,需要我們在每個方法中都添加相應的邏輯,這裏只存在一個方法所以工作量還不算大,假如Supplier接口中包含上百個方法呢?這時候使用靜態代理就會編寫許多冗餘代碼。通過使用動態代理,我們可以做一個“統一指示”,從而對所有代理類的方法進行統一處理,而不用逐一修改每個方法。代碼如下:

  首先供應商的接口和產品供應商類,與靜態代理中的一致:

package com.pattern.proxy.v2;
/**
 * 供應商總接口:定義了銷售產品的抽象方法
 * @author 
 *
 */
public interface Supplier {
   public void sellProduct();
}
package com.pattern.proxy.v2;
/**
 * 具體的產品供應商:實現了銷售產品的方式方法
 * @author 
 *
 */
public class ProductSupplier implements Supplier{
	@Override
	public void sellProduct() {
		System.out.println("ProductSupplier sell product...");
	}
}
微商代理類的定義:

package com.pattern.proxy.v2;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 動態代理類只能代理接口(不支持抽象類),代理類都需要實現InvocationHandler類,實現invoke方法。
 * 該invoke方法就是調用被代理接口的所有方法時需要調用的,該invoke方法返回的值是被代理接口的一個實現類  
 * 代理在銷售產品前,需要申請產品額度,銷售完畢後,需要及時記錄產品銷售額
 * @author 
 *
 */
public class MicroAgent implements InvocationHandler{
	private Object supplier;//代理類持有一個委託類對象引用

	public MicroAgent() {
	}
	//綁定關係,也就是關聯到哪個接口(與具體的實現類綁定)的哪些方法將被調用時,執行invoke方法。 
	public Object newProxyInstance(Object supplierTarget){
		this.supplier=supplierTarget;
		//該方法用於爲指定類裝載器、一組接口及調用處理器生成動態代理類實例    
        //第一個參數指定產生代理對象的類加載器,需要將其指定爲和目標對象同一個類加載器  
        //第二個參數要實現和目標對象一樣的接口,所以只需要拿到目標對象的實現接口  
        //第三個參數表明這些被攔截的方法在被攔截時需要執行哪個InvocationHandler的invoke方法  
        //根據傳入的目標返回一個代理對象
		return Proxy.newProxyInstance(Supplier.class.getClassLoader(), new Class[]{Supplier.class}, this);//返回代理類實例 
	}
	@Override
    /*InvocationHandler接口的方法,proxy表示代理,method表示原對象被調用的方法,args表示方法的參數*/  
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("i want 300 products....");//調用前申請產品額
		Object c=method.invoke(supplier, args);//調用目標方法
		System.out.println("i sell 190 products");//調用後記錄銷售額
		return c;
	}

}
客戶端測試類:

package com.pattern.proxy.v2;
/**
 * 客戶端測試類
 * @author 
 *
 */
public class ClientTest {
	public static void main(String[] args) {
		MicroAgent handler=new MicroAgent();//通過JDK動態代理獲取代理handler
		Supplier proxy=(Supplier)handler.newProxyInstance(new ProductSupplier());//獲取代理類的實例對象
		proxy.sellProduct();//代理類銷售產品
	}
}
      在代理類代碼中,newProxyInstance()方法返回Proxy.newProxyInstance()方法需要3個參數:類加載器ClassLoader(要進行代理的類)、被代理類實現的接口interfaces,事務處理器handler。代理類中,需要傳進一個ProductSupplier實例,根據實例和Handler動態生成代理對象,將各參數傳入Proxy的靜態方法newProxyInstance()即可獲得Supplier的代理類。靜態代理模式中,代理類是我們編寫好的,而動態代理則不需要我們去編寫代理類,是在程序中動態生成的。

  總結下來, JDK動態代理步驟如下:

  1. 創建被代理的類及接口:Supplier接口和ProductSupplier類
  2. 創建一個實現InvocationHandler接口的類,它必須實現invoke()方法,上述例子中爲MicroAgent類。

  3. 調用Proxy的靜態方法,創建一個代理類:Supplier proxy=(Supplier)handler.newProxyInstance(new ProductSupplier());//獲取代理類的實例對象

  4. 通過代理調用方法:proxy.sellProduct();//代理類銷售產品



源碼下載:http://download.csdn.net/download/pelifymeng2/9994734

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