程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 代理模式和JDK動態代理

代理模式和JDK動態代理

編輯:C++入門知識

代理模式和JDK動態代理


1.代理模式

在代理模式中,接活的就是代理,實際干事兒的就是被代理的對象,也就是說,接活的和干活的不是同一個對象。

這裡舉經典的火車站和火車票代售點為例來說明。

 

package testproxy;

public interface SellTicket {
	public void sellTicket();
}
SellTicket接口只有一個賣票的方法,凡是實現了該接口的類,都有賣票的能力。首先,火車站有賣票的能力:

 

 

package testproxy;

public class RailwayStation implements SellTicket {
	@Override
	public void sellTicket() {
		System.out.println(火車站售票);
	}

}
然後,火車票代售點有賣票的能力:

 

 

package testproxy;


public class RailwayStationProxy implements SellTicket {
	SellTicket sellTicket;
	
	public RailwayStationProxy() {
		this.sellTicket = new RailwayStation();
	}

	@Override
	public void sellTicket() {
		System.out.println(開始售票);
		this.sellTicket.sellTicket();
		System.out.println(售票成功);
	}

}
與火車站不同的是,火車票代售點自己並沒有票,實際上出票的是火車站。可見,代售點只是個接活的,也就是代理,火車站才是真正干活的對象,也就是被代理的對象。

 

下面是一個買票的客戶:

 

package testproxy;

public class Client {

	public static void main(String[] args) {
		SellTicket sellTicket = new RailwayStationProxy();
		sellTicket.sellTicket();
	}
}
客戶買票的過程是這樣的:

 

開始售票
火車站售票
售票成功

可見,代理參與了售票活動,但是真正出票的是火車站。

總結一下代理模式:代理和被代理對象都向外宣稱自己有干某件事的能力,供客戶調用,所以它們必須繼承同一個接口;但是,代理並沒有真正干某件事兒的能力,所以,他需要有一個對被代理對象的引用,當客戶讓它干事兒時,它就讓被代理對象去干。

2.JDK動態代理

JDK動態代理讓我們不用創建代理類就能創建一個代理對象。

代理對象是通過java.lang.reflect.Proxy類的靜態方法創建的:

newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h)

它的參數分別是類加載器、宣稱該代理有哪些能力的接口的Class數組和一個調用處理器。類加載器用於加載接口;調用處理器用於關聯代理對象和被代理對象。調用處理器有下面這個方法:

invoke(Object proxy, Method method, Object[] args)

proxy是代理對象,method是客戶端調用的代理對象的方法對應的Method對象,args是客戶端傳給調用方法的參數。客戶端每次調用代理對象上的方法,都會觸發調用處理器的invoke方法被調用。

這裡同樣用火車站和火車票代售點的例子來具體說明:

同樣有一個用於宣稱代理對象和被代理對象有何能力的接口:

 

package testproxy;

public interface SellTicket {
	public void sellTicket();
}

然後是確實有售票能力的火車站:

 

 

package testproxy;

public class RailwayStation implements SellTicket {
	@Override
	public void sellTicket() {
		System.out.println(火車站售票);
	}

}

要實現動態代理,我們還需要一個調用處理器:

 

 

package testproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class SellTicketHandler implements InvocationHandler {
	private Object target;
	
	public SellTicketHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println(開始售票);
		method.invoke(target);
		System.out.println(售票成功);
		return null;
	}

}

調用處理器的invoke方法調用了被代理對象上相應的方法。

 

接下來是在客戶端,在客戶端創建代理對象,並調用它上面的方法:

 

package testproxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxy {

	public static void main(String[] args) {
		RailwayStation railwayStation = new RailwayStation();
		InvocationHandler handler = new SellTicketHandler(railwayStation);
		Class[] interfaces = new Class[] {SellTicket.class};
		Object proxy = Proxy.newProxyInstance(handler.getClass().getClassLoader(), 
				interfaces, handler);
		try {
			Method method = SellTicket.class.getMethod(sellTicket);
			method.invoke(proxy);
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

運行結果:

 

開始售票
火車站售票
售票成功

 

最終總結:不管是代理模式,還是JDK的動態代理,都有這樣幾個元素:代理,被代理對象,以及宣稱它們能力的接口;只是動態代理不需要顯示創建代理類。

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved