衡水做wap網(wǎng)站互聯(lián)網(wǎng)培訓(xùn)
代理模式(Proxy Pattern)
一 定義
為其他對象提供一種代理,以控制對這個(gè)對象的訪問。
代理對象在客戶端和目標(biāo)對象之間起到了中介作用,起到保護(hù)或增強(qiáng)目標(biāo)對象的作用。
屬于結(jié)構(gòu)型設(shè)計(jì)模式。
代理模式分為靜態(tài)代理和動(dòng)態(tài)代理。
靜態(tài)代理是顯式聲明被代理對象,即硬編碼出來的代理結(jié)構(gòu);
動(dòng)態(tài)代理是動(dòng)態(tài)配置和替換被代理對象,即通過在jvm中生成一個(gè)代理類來實(shí)現(xiàn)代理。
代理模式標(biāo)準(zhǔn)示例:
頂層會有 subject的接口,RealSubject 和 Proxy 都實(shí)現(xiàn)了 Subject接口。
Proxy中,擁有 RealSubject對象的引用,在Proxy的構(gòu)造方法中,將RealSubject作為參數(shù)傳入,然后在Proxy 的同名方法中,調(diào)用 RealSubject的方法。但是在調(diào)用 RealSubject的方法前后,可以加入Proxy的自有邏輯。
上述類圖中各個(gè)類的代碼如下:
subject 接口類:ISubject
public interface ISubject{void request();
}
被代理的類:RealSubject
public class RealSubject implements ISubject{public void request(){System.out.println("real reqeust");}
}
代理類:Proxy
public class Proxy implements ISubject{private ISubject target;public Proxy(ISubject target){this.target = target;}public void request(){before();//調(diào)用前邏輯target.request();after();//調(diào)用后邏輯}
}
客戶端 ProxyClient
public class ProxyClient{public static void main(String[] args){Proxy proxy = new Proxy(new RealSubject());proxy.request();}
}
接下來,我們通過一個(gè)實(shí)際場景,來呈現(xiàn)出靜態(tài)代理與動(dòng)態(tài)代理的異同。
阿毛想租房,他首先考慮的是房產(chǎn)中介,因?yàn)榉吭醇性谥薪槟抢铩?/p>
首先是靜態(tài)代理的實(shí)現(xiàn):
租戶接口為:ITenant
中介類為:HouseProxy
實(shí)際租戶有兩個(gè)人:Amao
和 LaoSan
代碼如下:
public interface ITenant {void require();
}
public class HouseProxy implements ITenant{private ITenant custom;public HouseProxy(ITenant custom){this.custom = custom;}public void require() {before();custom.require();after();}private void before() {System.out.println("當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。");}private void after() {System.out.println("按照上述要求找到的房源有:xxx");System.out.println();}
}
public class Amao implements ITenant {public void require() {System.out.println("阿毛的要求:一室一廳,2樓,朝南,2000元以內(nèi)");}
}
public class LaoSan implements ITenant{public void require() {System.out.println("老三的要求:二室一廳,3樓以上,南北通透,4000元以內(nèi)");}
}
客戶端調(diào)用代碼:
public class Client {public static void main(String[] args) {//中介為阿毛找房:HouseProxy proxy = new HouseProxy(new Amao());proxy.require();//中介為老三找房:HouseProxy proxy1 = new HouseProxy(new LaoSan());proxy1.require();}
}
執(zhí)行結(jié)果為:
當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。
阿毛的要求:一室一廳,2樓,朝南,2000元以內(nèi)
按照上述要求找到的房源有:xxx當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。
老三的要求:二室一廳,3樓以上,南北通透,4000元以內(nèi)
按照上述要求找到的房源有:xxx
動(dòng)態(tài)代理的實(shí)現(xiàn)
由于租戶不是隨時(shí)可以看房,所以要和中介約好看房時(shí)間,所以我們在ITenant 接口中,增加了看房時(shí)間。
public interface ITenant {void require();void lookHouseTime();
}
相應(yīng)的,Amao和LaoSan 都需要實(shí)現(xiàn)這個(gè)方法:
public class Amao implements ITenant {public void require() {System.out.println("阿毛的要求:一室一廳,2樓,朝南,2000元以內(nèi)");}public void lookHouseTime() {System.out.println("阿毛看房時(shí)間:周末");}
}
public class LaoSan implements ITenant {public void require() {System.out.println("老三的要求:二室一廳,3樓以上,南北通透,4000元以內(nèi)");}public void lookHouseTime() {System.out.println("老三看房時(shí)間:周中");}
}
最后,是采用JDK動(dòng)態(tài)代理實(shí)現(xiàn)的HouseProxy:
public class JDKHouseProxy implements InvocationHandler {private ITenant custom;public ITenant getInstance(ITenant custom){this.custom = custom;Class<?> clazz = custom.getClass();return (ITenant) Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);}public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {if (!method.getName().equals("lookHouseTime")) {before();}Object result = method.invoke(this.custom,args);if (!method.getName().equals("lookHouseTime")) {after();}return result;}private void before() {System.out.println("--------------------");System.out.println("中介:當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。");}private void after() {System.out.println("中介:按照上述要求找到的房源有:xxx");}}
這里我們會發(fā)現(xiàn),使用動(dòng)態(tài)代理后,代理中介無需實(shí)現(xiàn)ITenant接口,如果ITenant接口發(fā)生變化,也不會對代理對象產(chǎn)生影響。
客戶端調(diào)用類:
public class Client {public static void main(String[] args) {//中介為阿毛找房:JDKHouseProxy proxy = new JDKHouseProxy();ITenant tenantAmao = proxy.getInstance(new Amao());tenantAmao.require();tenantAmao.lookHouseTime();//中介為老三找房:JDKHouseProxy proxy1 = new JDKHouseProxy();ITenant laosan = proxy1.getInstance(new LaoSan());laosan.require();laosan.lookHouseTime();}
}
執(zhí)行結(jié)果:
--------------------
中介:當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。
阿毛的要求:一室一廳,2樓,朝南,2000元以內(nèi)
中介:按照上述要求找到的房源有:xxx
阿毛看房時(shí)間:周末
--------------------
中介:當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。
老三的要求:二室一廳,3樓以上,南北通透,4000元以內(nèi)
中介:按照上述要求找到的房源有:xxx
老三看房時(shí)間:周中
動(dòng)態(tài)代理除了JDK的API之外,還有cglib的方式。
二者區(qū)別在于,JDK的動(dòng)態(tài)代理需要目標(biāo)對象有繼承體系(即實(shí)現(xiàn)接口);而cglib則不需要被代理對象存在繼承體系。
以下是cglib的示例:
cglib的中介代理類:CglibHouseProxy
public class CglibHouseProxy implements MethodInterceptor {public Object getInstance(Class<?> clazz){Enhancer enhancer = new Enhancer();enhancer.setSuperclass(clazz);enhancer.setCallback(this);return enhancer.create();}public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {if (!method.getName().equals("lookHouseTime")) {before();}Object result = proxy.invokeSuper(obj,args);if (!method.getName().equals("lookHouseTime")) {after();}return result;}private void before() {System.out.println("--------------------");System.out.println("中介:當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。");}private void after() {System.out.println("中介:按照上述要求找到的房源有:xxx");}
}
客戶端調(diào)用類:
public class CglibClient {public static void main(String[] args) {CglibHouseProxy proxy = new CglibHouseProxy();ITenant tenant = (ITenant) proxy.getInstance(Amao.class);tenant.require();tenant.lookHouseTime();}
}
執(zhí)行結(jié)果:
--------------------
中介:當(dāng)前代理權(quán)限通過驗(yàn)證,可以登錄系統(tǒng)開始篩選房源。
阿毛的要求:一室一廳,2樓,朝南,2000元以內(nèi)
中介:按照上述要求找到的房源有:xxx
阿毛看房時(shí)間:周末
補(bǔ)充:cglib pom.xml的引入
<dependency><groupId>cglib</groupId><artifactId>cglib-nodep</artifactId><version>2.2</version></dependency>
以上就是本文全部內(nèi)容。感謝您的閱讀。