代理模式對其他對象提供一種代理以控制對這個對象的訪問。
在某些情況下,一個對象不想或者不能直接引用另一個對象,而代理對象可以在客戶端和目標對象之間起到中介的作用。
代理模式的思想是為瞭提供額外的處理或者不同的操作而在實際對象與調用者之間插入一個代理對象。這些額外的操作通常需要與實際對象進行通信。
筆者總結代理模式的兩個核心內容:一是隔離訪問者對被訪問對象之間的直接交互,對被訪問對象的一切操作通過代理對象執行,這一點與裝飾模式和外觀模式類似;另一方面代理對象對被代理對象的業務邏輯作出修改,可以增加、屏蔽部分業務邏輯,這一點是裝飾和外觀模式所不允許的。
代理模式應用最多的場景是對業務訪問進行前置和後置處理。 舉一個唱歌的例子,原來有一個歌手唱歌的對象,現在歌手要登臺演出,唱歌前後要加上報幕和謝幕的動作。歌手不是每次都是登臺演出,所以直接修改唱歌的類加上報幕和謝幕的操作顯然不合適,這裡使用代理模式來解決這個問題:
[java]
interface Sing {
void sing();
}
class Fancy implements Sing {
@Override
void sing() {
System.out.println("唱歌!");
}
}
public class FancyProxy implements Sing {
Sing singger;
public FancyProxy(Sing singger) {
this.singger = singger;
}
@Override
public void sing() {
//報幕
baoMu();
//唱歌
singger.sing();
//謝幕
xieMu();
}
}
上面的方式很好的解決瞭登臺演出的問題,但這樣解決方法必須在設計階段完成,具有很大的局限性。JDK提供瞭動態創建代理的工具,使得我們在運行時可以生成對象的代理,與上面的代碼不同,這裡就是我們常說的動態代理:www.aiwalls.com
[java]
class DynamicProxy implements InvocationHandler {
private Object target;
public DynamicProxy(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before calling " + method);
method.invoke(target, args);
System.out.println("after calling " + method);
return null;
}
static void main(String[] args) {
Fancy fancy = new Fancy(); // 在這裡指定被代理類
InvocationHandler handler = new DynamicProxy(fancy); // 初始化代理類
Class cls = fancy.getClass();
Sing sing = (Sing) Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), handler);
sing.sing();
}
}
通過這種方式,被代理的對象(Fancy)可以在運行時動態改變,需要控制的接口(Sing接口)可以在運行時改變,控制的方式(DynamicProxy類)也可以動態改變,從而實現瞭非常靈活的動態代理關系。
作者:fancy888