本篇內(nèi)容介紹了“什么是代理模式”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
烏達(dá)ssl適用于網(wǎng)站、小程序/APP、API接口等需要進(jìn)行數(shù)據(jù)傳輸應(yīng)用場(chǎng)景,ssl證書未來市場(chǎng)廣闊!成為成都創(chuàng)新互聯(lián)的ssl證書銷售渠道,可以享受市場(chǎng)價(jià)格4-6折優(yōu)惠!如果有意向歡迎電話聯(lián)系或者加微信:13518219792(備注:SSL證書合作)期待與您的合作!
整個(gè)過程用代碼展示如下:
/** * 鞋廠接口 */ public interface IShoesFactory { /** * 參觀工廠 */ void visitFactory(); /** * 下訂單 * @param price 金額 */ void placeOrder(double price); /** * 發(fā)貨 */ void ship(); }
/** * 鞋廠類 */ public class ShoesFactory implements IShoesFactory{ private String name; public ShoesFactory(String name) { this.name = name; } /** * 參觀工廠 */ @Override public void visitFactory() { System.out.println("帶客戶參觀" + name); } /** * 下訂單 * * @param price 金額 */ @Override public void placeOrder(double price) { System.out.println("接到" + price + "元的訂單"); } /** * 發(fā)貨 */ @Override public void ship() { System.out.println("開始發(fā)貨"); } }
/** * 代理鞋廠類 */ public class ShoesFactoryProxy implements IShoesFactory{ private IShoesFactory shoesFactory; public ShoesFactoryProxy(IShoesFactory shoesFactory) { this.shoesFactory = shoesFactory; } /** * 參觀工廠 */ @Override public void visitFactory() { shoesFactory.visitFactory(); } /** * 下訂單 * * @param price 金額 */ @Override public void placeOrder(double price) { shoesFactory.placeOrder(price); } /** * 發(fā)貨 */ @Override public void ship() { shoesFactory.ship(); } }
客戶類:
public class Client { public static void main(String[] args) { IShoesFactory factory = new ShoesFactory("劉望星的工廠"); IShoesFactory factoryProxy = new ShoesFactoryProxy(factory); // 參觀工廠 factoryProxy.visitFactory(); // 下訂單 factoryProxy.placeOrder(10000); // 發(fā)貨 factoryProxy.ship(); } }
輸出結(jié)果:
帶客戶參觀劉望星的工廠 接到10000.0元的訂單 開始發(fā)貨
客戶要參觀工廠,小帥就帶客戶去參觀劉望星的工廠,和客戶說這就是自己的工廠??蛻粝蛐浵聠危浘桶延唵蜗陆o劉望星生產(chǎn)。
客戶類調(diào)用代理的方法,代理類再調(diào)用業(yè)務(wù)類的方法完成工作。
代理模式(Proxy Pattern) :給某一個(gè)對(duì)象提供一個(gè)代理,并由代理對(duì)象控制對(duì)原對(duì)象的引用。 代理模式的英語叫Proxy,它是一種結(jié)構(gòu)型模式。
代理背后一般至少有一個(gè)實(shí)際對(duì)象,代理的外部功能和實(shí)際對(duì)象一般是一樣的,用戶與代理打交道,不直接接觸實(shí)際對(duì)象,甚至不知道實(shí)際對(duì)象的存在。
代理模式到底有什么用呢?難道僅僅是通過代理類做個(gè)轉(zhuǎn)發(fā)嗎?
當(dāng)然不是的,雖然外部功能和實(shí)際對(duì)象一樣,但代理有它存在的價(jià)值,代理也分為多種類型比如:
遠(yuǎn)程(Remote)代理:適用于調(diào)用遠(yuǎn)程服務(wù)器對(duì)象的情況,代理通過網(wǎng)絡(luò)傳遞客戶端請(qǐng)求, 負(fù)責(zé)處理所有與網(wǎng)絡(luò)相關(guān)的復(fù)雜細(xì)節(jié),簡(jiǎn)化了客戶端的調(diào)用。
虛擬(Virtual)代理:如果需要?jiǎng)?chuàng)建一個(gè)資源消耗較大的對(duì)象,先創(chuàng)建一個(gè)消耗相對(duì)較小的對(duì)象來表示,真實(shí)對(duì)象只在需要時(shí)才會(huì)被真正創(chuàng)建。
Copy-on-Write代理:它是虛擬代理的一種,把復(fù)制(克?。┎僮餮舆t到只有在客戶端真正需要時(shí)才執(zhí)行。一般來說,對(duì)象的深克隆是一個(gè) 開銷較大的操作,Copy-on-Write代理可以讓這個(gè)操作延遲,只有對(duì)象被用到的時(shí)候才被克隆。
保護(hù)(Protect or Access)代理:控制對(duì)一個(gè)對(duì)象的訪問,可以給不同的用戶提供不同級(jí)別的使用權(quán)限。
緩沖(Cache)代理:為某一個(gè)目標(biāo)操作的結(jié)果提供臨時(shí)的存儲(chǔ)空間,以便多個(gè)客戶端可以共享這些結(jié)果。
防火墻(Firewall)代理:保護(hù)目標(biāo)不讓惡意用戶接近。
同步化(Synchronization)代理:使幾個(gè)用戶能夠同時(shí)使用一個(gè)對(duì)象而沒有沖突。
智能引用(Smart Reference)代理:當(dāng)一個(gè)對(duì)象被引用時(shí),提供一些額外的操作,如將此對(duì)象被調(diào)用的次數(shù)記錄下來等。
我們來看看幾個(gè)例子:
保護(hù)(Protect or Access)代理的作用是,控制對(duì)一個(gè)對(duì)象的訪問,可以給不同的用戶提供不同級(jí)別的使用權(quán)限。
如果我們不想客戶訪問某個(gè)功能,就可以在代理類里做手腳,畢竟業(yè)務(wù)類都是通過代理類調(diào)用的嘛。
比如,小帥怕露餡,不想讓客戶參觀工廠,就可以改寫參觀工廠的方法:
輸出:
工廠禁止參觀 接到10000.0元的訂單 開始發(fā)貨
智能引用(Smart Reference)代理的作用是,當(dāng)一個(gè)對(duì)象被引用時(shí),提供一些額外的操作,如將此對(duì)象被調(diào)用的次數(shù)記錄下來等。
比如,小帥作為代理商,肯定是要賺錢的,客戶下了一個(gè)10000元的訂單,小帥就和劉望星談好提成10%,就可以在代理類中把金額扣掉。
還有,小帥的工廠有自己的品牌,發(fā)貨之前還要貼上自己的牌子。
輸出:
工廠禁止參觀 接到9000.0元的訂單 貼上小帥牌標(biāo)簽。 開始發(fā)貨
圖片代理:一個(gè)很常見的代理模式的應(yīng)用實(shí)例就是對(duì)大圖瀏覽的控制。用戶通過瀏覽器訪問網(wǎng)頁時(shí)先不加載真實(shí)的大圖,而是通過代理對(duì)象的方法來進(jìn)行處理。
在代理對(duì)象的方法中,先使用一個(gè)線程向客戶端瀏覽器加載一個(gè)小圖片,然后在后臺(tái)使用另一個(gè)線程來調(diào)用大圖片的加載方法將大圖片加載到客戶端。當(dāng)需要瀏覽大圖片時(shí),再將大圖片在新網(wǎng)頁中顯示。
如果用戶在瀏覽大圖時(shí)加載工作還沒有完成,可以再啟動(dòng)一個(gè)線程來顯示相應(yīng)的提示信息。通過代理技術(shù)結(jié)合多線程編程將真實(shí)圖片的加載放到后臺(tái)來操作,不影響前臺(tái)圖片的瀏覽。
遠(yuǎn)程代理:遠(yuǎn)程代理可以將網(wǎng)絡(luò)的細(xì)節(jié)隱藏起來,使得客戶端不必考慮網(wǎng)絡(luò)的存在。客戶完全可以認(rèn)為被代理的遠(yuǎn)程業(yè)務(wù)對(duì)象是局域的而不是遠(yuǎn)程的,而遠(yuǎn)程代理對(duì)象承擔(dān)了大部分的網(wǎng)絡(luò)通信工作。
虛擬代理:當(dāng)一個(gè)對(duì)象的加載十分耗費(fèi)資源的時(shí)候,虛擬代理的優(yōu)勢(shì)就非常明顯地體現(xiàn)出來了。虛擬代理模式是一種內(nèi)存節(jié)省技術(shù),那些占用大量?jī)?nèi)存或處理復(fù)雜的對(duì)象將推遲到使用它的時(shí)候才創(chuàng)建。
上面說的這些方法是靜態(tài)代理模式,真實(shí)的業(yè)務(wù)類必須是事先已經(jīng)創(chuàng)建好的的,并把它傳給代理對(duì)象,作為一個(gè)內(nèi)部成員。
靜態(tài)代理是這樣子的:
如果一個(gè)真實(shí)業(yè)務(wù)類必須對(duì)應(yīng)一個(gè)代理類,這將導(dǎo)致系統(tǒng)中的代理類的個(gè)數(shù)急劇增加,比如有10個(gè)不同的業(yè)務(wù)類,那么必須要有10個(gè)對(duì)應(yīng)的代理類,因此需要想辦法減少系統(tǒng)中類的個(gè)數(shù)。
動(dòng)態(tài)代理可以在事先不知道真實(shí)業(yè)務(wù)類的情況下使用代理類,在程序運(yùn)行期間由JVM根據(jù)反射等機(jī)制動(dòng)態(tài)的生成,動(dòng)態(tài)代理的典型應(yīng)用就是Spring AOP。
下面我們看一下Java SDK動(dòng)態(tài)代理的例子:
/** * 鞋廠接口 */ public interface IShoesFactory { /** * 參觀工廠 */ void visitFactory(); /** * 下訂單 * @param price 金額 */ void placeOrder(double price); /** * 發(fā)貨 */ void ship(); }
/** * 鞋廠類 */ public class ShoesFactory implements IShoesFactory { private String name; public ShoesFactory(String name) { this.name = name; } /** * 參觀工廠 */ @Override public void visitFactory() { System.out.println("帶客戶參觀" + name); } /** * 下訂單 * * @param price 金額 */ @Override public void placeOrder(double price) { System.out.println("接到" + price + "元的訂單"); } /** * 發(fā)貨 */ @Override public void ship() { System.out.println("開始發(fā)貨"); } }
InvocationHandler接口是proxy代理實(shí)例的調(diào)用處理程序?qū)崿F(xiàn)的一個(gè)接口,代理類每調(diào)用一次方法就會(huì)進(jìn)入這里的invoke方法。
public class ShoesFactoryHandler implements InvocationHandler { /** * 被代理的對(duì)象,實(shí)際的方法執(zhí)行者 */ private Object proxiedObject; public ShoesFactoryHandler(Object proxiedObject) { this.proxiedObject = proxiedObject; } /** * 代理類每調(diào)用一次方法就會(huì)進(jìn)入這里 * @param proxy 表示代理對(duì)象本身,需要注意,它不是被代理的對(duì)象 * @param method 表示正在被調(diào)用的方法 * @param args 表示方法的參數(shù) * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /*if(method.getName().equals("visitFactory")) { System.out.println("工廠禁止參觀"); }*/ if(method.getName().equals("placeOrder")) { // 如果是下訂單方法,給代工廠9折的價(jià)格 method.invoke(proxiedObject, Double.parseDouble(String.valueOf(args[0])) * 0.9); } else if(method.getName().equals("ship")) { // 如果是發(fā)貨方法,發(fā)貨之前先貼上標(biāo)簽 System.out.println("貼上小帥牌標(biāo)簽"); method.invoke(proxiedObject, args); } else { // 其他方法,直接調(diào)用 method.invoke(proxiedObject, args); } return null; } }
Proxy類調(diào)用newProxyInstance方法來創(chuàng)建一個(gè)代理對(duì)象,上面的InvocationHandler對(duì)象作為參數(shù)之一。
public class ShoesFactoryProxy { /** * 生成動(dòng)態(tài)代理 * @param proxiedObject 被代理的對(duì)象,實(shí)際的方法執(zhí)行者 * @return */ public Object createProxy(Object proxiedObject) { // 獲取對(duì)應(yīng)的ClassLoader ClassLoader classLoader = proxiedObject.getClass().getClassLoader(); // 獲取所有的接口 Class[] interfaces = proxiedObject.getClass().getInterfaces(); // 創(chuàng)建一個(gè)傳給代理類的調(diào)用請(qǐng)求處理器 ShoesFactoryHandler handler = new ShoesFactoryHandler(proxiedObject); return Proxy.newProxyInstance(classLoader, interfaces, handler); } }
客戶端類:
public class Client { public static void main(String[] args) { IShoesFactory factory = new ShoesFactory("劉望星的工廠"); ShoesFactoryProxy shoesFactoryProxy = new ShoesFactoryProxy(); IShoesFactory factoryProxy = (IShoesFactory)shoesFactoryProxy.createProxy(factory); // 參觀工廠 factoryProxy.visitFactory(); // 下訂單 factoryProxy.placeOrder(10000); // 發(fā)貨 factoryProxy.ship(); } }
輸出結(jié)果:
帶客戶參觀劉望星的工廠 接到9000.0元的訂單 貼上小帥牌標(biāo)簽 開始發(fā)貨
通用性更強(qiáng)些的動(dòng)態(tài)代理類一般是這樣的:
public class NormalHandler implements InvocationHandler { /** * 被代理的對(duì)象,實(shí)際的方法執(zhí)行者 */ private Object proxiedObject; public NormalHandler(Object proxiedObject) { this.proxiedObject = proxiedObject; } /** * 代理類每調(diào)用一次方法就會(huì)進(jìn)入這里 * @param proxy 表示代理對(duì)象本身,需要注意,它不是被代理的對(duì)象 * @param method 表示正在被調(diào)用的方法 * @param args 表示方法的參數(shù) * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 調(diào)用實(shí)際方法之前的操作 preRequest(); // 調(diào)用實(shí)際方法 Object result = method.invoke(proxiedObject, args); // 調(diào)用實(shí)際方法之后的操作 afterRequest(); } return result; } }
這樣,我們就能在preRequest()和afterRequest()方法中做很多事情了,比如記錄日志,記錄調(diào)用時(shí)間等等。
代理模式看上去和裝飾者模式很像,不過它們的意圖是不一樣的,裝飾者模式是為對(duì)象加上新的行為,而代理模式是作為真實(shí)對(duì)象的替身,控制對(duì)象的訪問。
比如,保護(hù)代理,進(jìn)行權(quán)限控制,不讓客戶訪問某些功能;比如,虛擬代理,在真實(shí)的對(duì)象創(chuàng)建之前,先返回預(yù)定設(shè)定好的信息。
下面我們來看看代理模式的優(yōu)點(diǎn)和缺點(diǎn):
代理模式能夠協(xié)調(diào)調(diào)用者和被調(diào)用者,在一定程度上降低了系統(tǒng)的耦合度。
你可以在客戶端毫無察覺的情況下控制服務(wù)對(duì)象。
即使服務(wù)對(duì)象還未準(zhǔn)備好或不存在, 代理也可以正常工作。
符合開閉原則, 你可以在不對(duì)服務(wù)或客戶端做出修改的情況下創(chuàng)建新代理。
由于在客戶端和真實(shí)業(yè)務(wù)類之間增加了代理對(duì)象,因此有些類型的代理模式可能會(huì)造成請(qǐng)求的處理速度變慢。
實(shí)現(xiàn)代理模式需要額外的工作,增加了程序的復(fù)雜度。
“什么是代理模式”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!