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;
}
}
接下來是在客戶端,在客戶端創建代理對象,並調用它上面的方法:
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的動態代理,都有這樣幾個元素:代理,被代理對象,以及宣稱它們能力的接口;只是動態代理不需要顯示創建代理類。