定義:爲其餘對象提供一種代理以控制對這個對象的訪問java
上圖中,Subject是一個抽象類或者接口,RealSubject是實現方法類,具體的業務執行,Proxy則是RealSubject的代理,直接和client接觸的。git
代理模式能夠在不修改被代理對象的基礎上,經過擴展代理類,進行一些功能的附加與加強。值得注意的是,代理類和被代理類應該共同實現一個接口,或者是共同繼承某個類。github
代碼:GitHubshell
以租房爲例,咱們通常用租房軟件、找中介或者找房東。這裏的中介就是代理者。編程
首先定義一個提供了租房方法的接口。微信
public interface IRentHose {
void rentHose();
}
複製代碼
定義租房的實現類ide
public class RentHose implements IRentHose {
@Override
public void rentHose() {
System.out.println("租了一間房子。。。");
}
}
複製代碼
我要租房,房源都在中介手中,因此找中介測試
public class IntermediaryProxy implements IRentHose {
private IRentHose rentHose;
public IntermediaryProxy(IRentHose irentHose){
rentHose = irentHose;
}
@Override
public void rentHose() {
System.out.println("交中介費");
rentHose.rentHose();
System.out.println("中介負責維修管理");
}
}
複製代碼
這裏中介也實現了租房的接口。this
再main方法中測試spa
public class Main {
public static void main(String[] args){
//定義租房
IRentHose rentHose = new RentHose();
//定義中介
IRentHose intermediary = new IntermediaryProxy(rentHose);
//中介租房
intermediary.rentHose();
}
}
複製代碼
返回信息
交中介費
租了一間房子。。。
中介負責維修管理
複製代碼
這就是靜態代理,由於中介這個代理類已經事先寫好了,只負責代理租房業務
若是咱們直接找房東要租房,房東會說我把房子委託給中介了,你找中介去租吧。這樣咱們就又要交一部分中介費了,真坑。
來看代碼如何實現,定義一個租房接口,增長一個方法。
public interface IRentHose {
void rentHose();
IRentHose getProxy();
}
複製代碼
這時中介的方法也稍微作一下修改
public class IntermediaryProxy implements IRentHose {
private IRentHose rentHose;
public IntermediaryProxy(IRentHose irentHose){
rentHose = irentHose;
}
@Override
public void rentHose() {
rentHose.rentHose();
}
@Override
public IRentHose getProxy() {
return this;
}
}
複製代碼
其中的getProxy()方法返回中介的代理類對象
咱們再來看房東是如何實現租房:
public class LandLord implements IRentHose {
private IRentHose iRentHose = null;
@Override
public void rentHose() {
if (isProxy()){
System.out.println("租了一間房子。。。");
}else {
System.out.println("請找中介");
}
}
@Override
public IRentHose getProxy() {
iRentHose = new IntermediaryProxy(this);
return iRentHose;
}
/** * 校驗是不是代理訪問 * @return */
private boolean isProxy(){
if(this.iRentHose == null){
return false;
}else{
return true;
}
}
}
複製代碼
房東的getProxy方法返回的是代理類,而後判斷租房方法的調用者是不是中介,不是中介就不租房。
main方法測試:
public static void main(String[] args){
IRentHose iRentHose = new LandLord();
//租客找房東租房
iRentHose.rentHose();
//找中介租房
IRentHose rentHose = iRentHose.getProxy();
rentHose.rentHose();
}
}
複製代碼
請找中介
租了一間房子。。。
複製代碼
看,這樣就是強制你使用代理,若是不是代理就無法訪問。
咱們知道如今的中介不單單是有租房業務,同時還有賣房、家政、維修等得業務,只是咱們就不能對每個業務都增長一個代理,就要提供通用的代理方法,這就要經過動態代理來實現了。
中介的代理方法作了一下修改
public class IntermediaryProxy implements InvocationHandler {
private Object obj;
public IntermediaryProxy(Object object){
obj = object;
}
/** * 調用被代理的方法 * @param proxy * @param method * @param args * @return * @throws Throwable */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(this.obj, args);
return result;
}
}
複製代碼
在這裏實現InvocationHandler接口,此接口是JDK提供的動態代理接口,對被代理的方法提供代理。其中invoke方法是接口InvocationHandler定義必須實現的, 它完成對真實方法的調用。動態代理是根據被代理的接口生成全部的方法,也就是說給定一個接口,動態代理就會實現接口下全部的方法。經過 InvocationHandler接口, 全部方法都由該Handler來進行處理, 即全部被代理的方法都由 InvocationHandler接管實際的處理任務。
這裏增長一個賣房的業務,代碼和租房代碼相似。
main方法測試:
public static void main(String[] args){
IRentHose rentHose = new RentHose();
//定義一個handler
InvocationHandler handler = new IntermediaryProxy(rentHose);
//得到類的class loader
ClassLoader cl = rentHose.getClass().getClassLoader();
//動態產生一個代理者
IRentHose proxy = (IRentHose) Proxy.newProxyInstance(cl, new Class[]{IRentHose.class}, handler);
proxy.rentHose();
ISellHose sellHose = new SellHose();
InvocationHandler handler1 = new IntermediaryProxy(sellHose);
ClassLoader classLoader = sellHose.getClass().getClassLoader();
ISellHose proxy1 = (ISellHose) Proxy.newProxyInstance(classLoader, new Class[]{ISellHose.class}, handler1);
proxy1.sellHose();
}
複製代碼
租了一間房子。。。
買了一間房子。。。
複製代碼
在main方法中咱們用到了Proxy這個類的方法,
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) 複製代碼
loder:類加載器,interfaces:代碼要用來代理的接口, h:一個 InvocationHandler 對象 。
InvocationHandler 是一個接口,每一個代理的實例都有一個與之關聯的 InvocationHandler 實現類,若是代理的方法被調用,那麼代理便會通知和轉發給內部的 InvocationHandler 實現類,由它決定處理。
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
}
複製代碼
InvocationHandler 內部只是一個 invoke() 方法,正是這個方法決定了怎麼樣處理代理傳遞過來的方法調用。
由於,Proxy 動態產生的代理會調用 InvocationHandler 實現類,因此 InvocationHandler 是實際執行者。
歡迎關注: