1. 程式人生 > >java設計模式---(3)代理模式

java設計模式---(3)代理模式

代理模式就是這個事情是A的,A自己不做就B去代他做。代理模式分2種情況:簡單的靜態代理和稍微複雜的動態代理。

  • 靜態代理

例項:
有個老師:

public class Teacher {
	public void teach(String teach) {
		System.out.println("我是老師我在講課,講:" + teach);
	}
}

有個助教:

public class Assistant {
	public void beforeTeach(){
		System.out.println("我是助教,講課前 老師要我幫他 備課");
	}
	
	public void afterTeach(){
		System.out.println("我是助教,講課後 老師要我幫他 收作業");
	}
}

之前這個老師在學校上課都是上課鈴響了再顛進來,直接開口就講,講完就閃人的。現在學校規則變了,要求講課前要先備課,講課後要學生交作業,老師收作業。但是這個老師他不愛備課呀,佈置了作業也不愛批改呀,怎麼辦呢,這裡就只能請個助教,再整個新的上課模式-----代理上課了:

public class TeachProxy {

	private Teacher teacher;
	
	private Assistant assistant;
	
	TeachProxy(Teacher teacher,Assistant assistant){
		this.teacher = teacher;
		this.assistant = assistant;
	}
	
	public void teach(String teach){
		assistant.beforeTeach();
		teacher.teach(teach);
		assistant.afterTeach();
	}
}

在代理上課模式中,上課還是這個老師上,而課前課後的這些他不愛乾的事情就都給助教了。所以現在的上課方式就是這樣的:

public class MainTest {
	public static void main(String[] args) {
		TeachProxy tp = new TeachProxy(new Teacher(), new Assistant());
		tp.teach("《大學》");
	}
}

輸出:

我是助教,講課前 要我 備課
我是老師我在講課,講:《大學》
我是助教,講課後 要我 收作業

上面就是代理模式的基本思路,A(老師)不自己去做事(自己new Teacher物件,呼叫teach()方法),而是把事情代理給B(TeachProxy )去做,然後B在幫A做事的時候就可以自己插入一些額外的操作。

再簡化一點代理模式可以寫成這樣:

public class TeachProxy {
	private Teacher teacher;
	
	TeachProxy(Teacher teacher){
		this.teacher = teacher;
	}
	public void teach(String teach){
		teacher.teach(teach);
	}
}

public class MainTest {
	public static void main(String[] args) {
		TeachProxy tp = new TeachProxy(new Teacher());
		tp.teach("《大學》");
	}
}

不要助教了,就是代理類TeachProxy來代老師類來呼叫這個teach()方法,當然一般都不會這樣寫,代理類的作用與被代理類完全一樣是那不就不用代理了,所以一般都會在代理的過程中去加點什麼,這裡只是便於理解。

  • 動態代理
    用jdk的動態代理,具體就是要用到java.lang.reflect.Proxy這個類。用這個來實現上面的那個只願意講課的老師把他的課前課後的事都甩給助教。老師和助教的2個類都不變,另外還要將老師這個類抽象出一個接口出來:
public interface ITeacher {
	void teach(String teach);
}

下面是代理類:

public class ProxyDynamic implements InvocationHandler {

	private Object A; // 被代理的類,這裡一會就是Teacher
	
	private Object C; // 插入的類 , 這裡一會就是Assistant

	ProxyDynamic(Object a,Object c) {
		this.A = a;
		this.C = c;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		C.getClass().getDeclaredMethod("before").invoke(C); // 執行助教的方法
		Object invoke = method.invoke(this.A, args); // 執行代理類,也就是老師的方法
		C.getClass().getDeclaredMethod("after").invoke(C); // 執行助教的方法
		return invoke;
	}

}

這裡代理類實現了一個介面java.lang.reflect.InvocationHandler然後override了他的invoke()方法,正是這個invoke()方法來幫助代理的類來執行類裡面的方法(這裡就是Teacher類中的teach()方法)。
下面是呼叫:

	public static void main(String[] args) {
		Teacher t = new Teacher(); // 老師--被代理的物件
		Assistant a = new Assistant(); // 助教--代理類中做點其他什麼事的物件
		InvocationHandler handler = new ProxyDynamic(t, a); // 自己定義的代理
		ITeacher teacher = (ITeacher) Proxy.newProxyInstance(t.getClass().getClassLoader(),
				t.getClass().getInterfaces(), handler);
		teacher.teach("《大學》");
	}

輸出跟上面的一樣:

我是助教,講課前 要我 備課
我是老師我在講課:《大學》
我是助教,講課後 要我 收作業

大概的說明一下newProxyInstance方法:
newProxyInstance方法
介面說明:返回指定介面的代理類的例項,該介面將方法呼叫分派給指定的呼叫處理程式。3個引數分別是:
loader:代理類的類載入器
interfaces:代理類的介面列表
h:自己定義的handler,用於方法呼叫
返回值:返回一個指定了方法呼叫的handler的代理類例項,這個代理類指定了類載入器並且實現了指定的具體介面。說白了就是返回一個代理類的例項,這個例項的三個參(類載入器、代理類的介面列表、handler)數都要指定好。