代理模式的定義
爲其他對象提供一種代理,以控制對這個對象的訪問;
代理對象起到中介的作用,可去掉功能服務或者增加額外的服務;
比如:買火車票,可以去火車票代售處購買而不用非得去到火車站,火車票代售處就是火車站的代理,
火車票代售處和火車站的功能的比較:
功能服務 | 火車站 | 火車票代售處 |
---|---|---|
火車票的銷售功能 | 有 | 有 |
提供額外的服務(電話預約) | 沒有 | 有 |
提供額外的服務(收取手續費) | 沒有 | 有 |
提供退票服務 | 有 | 沒有 |
火車票代售處就是火車站的代理,可去掉功能服務或者增加額外的服務;
代理模式兩種靜態代理和動態代理
靜態代理
比如一輛汽車有行駛功能,現在要代理一下汽車行駛,額外增加時間記錄功能;
1,相同接口或抽象類
public interface Moveable {
void move();//公共的行駛
}
//原始的小汽車 實現了Moveable
public class Car implements Moveable {
@Override
public void move() {
System.out.println("汽車行駛過程中。。。。。");
}
}
通過繼承來實現代理
現在的代理小汽車實現了 Moveable (Car本身也是實現了Moveable)
//通過繼承的方式來實現代理
public class CarProxy1 extends Car {
@Override
public void move() {
System.out.println("汽車開始時間。。。。。");//額外增加時間統計
super.move();
System.out.println("汽車結束時間。。。。。");
}
}
通過聚合來實現代理
現在的代理小汽車實現了 Moveable
public class CarProxy2 implements Moveable {
public Moveable m;
public CarProxy2(Car m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽車開始時間。。。。。");//額外增加時間統計
m.move();
System.out.println("汽車結束時間。。。。。");
}
}
繼承的方式相比於聚合來講不靈活;
現在我們添加一個代理日誌打印的功能;使用繼承的方式會增加下面四中代理類,每個代理類的都是特定的功能如下;
1,統計時間的代理類;
2,統計日誌的代理類;
3,先統計時間後統計日誌的代理類;
4,先統計日誌後統計時間的代理類;
如果使用組合的話,只需要兩個類就可以了;看代碼
1,統計時間代理類
//代理時間打印的代理
public class CarTimeProxy implements Moveable {
public Moveable m;
public CarTimeProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽車開始時間。。。。。");//額外增加時間統計
m.move();
System.out.println("汽車結束時間。。。。。");
}
}
統計時間代理類
Car car = new Car();
CarTimeProxy carTimeProxy = new CarTimeProxy(car);
carTimeProxy.move();
2,統計日誌代理類
//代理日誌打印功能的代理
public class CarLogProxy implements Moveable {
public Moveable m;
public CarLogProxy(Moveable m) {
this.m = m;
}
@Override
public void move() {
System.out.println("汽車開始日誌。。。。。");//額外增加日誌打印統計
m.move();
System.out.println("汽車結束日誌。。。。。");
}
}
統計日誌打印代理類
Car car = new Car();
CarLogProxy carLogProxy = new CarLogProxy(car);
carLogProxy.move();
3,先統計時間後統計日誌的代理
Car car = new Car();
CarTimeProxy carTimeProxy = new CarTimeProxy(car);
CarLogProxy carLogProxy = new CarLogProxy(carTimeProxy);
carLogProxy.move();
4,先統計日誌後統計時間的代理
Car car = new Car();
CarLogProxy carLogProxy = new CarLogProxy(car);
CarTimeProxy carTimeProxy = new CarTimeProxy(carLogProxy);
carTimeProxy.move();
從上面看使用組合方式只需要使用2個類就ok了;
動態代理
上面的小汽車需要做時間上的代理,那麼自行車,火車,也需要時間上的代理,其它失誤也需要時間上的代理,如下圖所示,有一百個事物就需要做100個事物對象的時間代理;
那樣會造成代理類膨脹;那麼有沒有一種方式 實現對不同類,不同方法的代理這產生裏動態代理,
上面的事例中不同的想要代理時間的對象都是動態產生,這就屬於動態代理;
動態代理就是在代理對象和被代理對象之間添加了一個事物處理器;如下圖代理的關鍵兩個類:
Proxy:
InVocationHandler:
具體代碼實現:
//這個Car類,現在要對它做一個時間代理(使用動態代理)
final Car car = new Car();
//實現一個InvocationHandler接口
InvocationHandler invocationHandler = new InvocationHandler() {
/**
* @param proxy 代理類Proxy,它是JDK內部的類
* @param method 被代理類的方法
* @param args 被代理類方法的參數
* @return 被代理類的方法返回值
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("汽車行駛開始時間。。。。。");
method.invoke(car, args);
System.out.println("汽車行駛結束時間。。。。。");
return null;
}
};
ClassLoader classLoader = Car.class.getClassLoader();
Class<?>[] interfaces = Car.class.getInterfaces();
//產生一個代理對象
final Moveable m = (Moveable) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
//調用方法,就會調用InvocationHandler的invoke方法,整個代理過程都在這個方法裏面執行
m.move();
總結動態代理:這個鬼東西真的很玄幻啊,我剛開始是很暈暈的,
使用一個僞代碼解釋一下,
public class CarProxy implements Moveable{
InvocationHandler invocationHandler;
@Override
public void move() {
invocationHandler.invoke()
}
}
1,Proxy.newProxyInstance生成的代理類class是在運行時生成,
Proxy.newProxyInstance()生成的就是一個類似上面的代理類CarProxy,裏面含有InvocationHandler屬性
2,Proxy.newProxyInstance生成的代理類class需要實現一組接口
這裏這個代理類CarProxy也是實現了Moveable接口
3,必須實現InvocationHandler,具體代理類業務是在invoke方法裏面實現;
當代理類CarProxy調用自己的方法比如move()時候,相當於這個時候InvocationHandler調用自己的invoke方法來執行的;