Java设计模式(13)----------代理模式
原文:https://www.imooc.com/article/24850
默課道可工程師學習地址:https://www.imooc.com/article/24850
介紹
代理模式中,在客戶端與對象之間增加了一個代理層。客戶端在進行訪問時候,不是直接訪問對象,而是訪問代理。代理模式是一種結構型的設計模式。通過代理模式,可以解決直接訪問對象帶來的一些問題,并且可以進行訪問控制。
代理模式的實現中,代理類中依賴實體類,但兩者共同實現相同的接口。代理類中對應接口中,會調用實體類的對應接口。聽上去與裝飾器的實現一樣,是的,兩者的實現基本上是相同的,只是使用意義上的側重點不同。兩者的區別,會在文末的總結中進行分析。
代理模式的應用場景比較廣泛,跟“代理”兩個字沾邊的,一般都會涉及代理模式。比如火車票代售站,對于乘客來說,他不需要去真正的火車站,而通過代售點,就可以實現買票取票的功能。比如VPN,由于眾所周知的原因,我們不能訪問youtube,那么我們可以設置一個VPN,通過VPN進行訪問。再比如說windows的快捷方式,也是一種代理。還有就是Spring的AOP。
代理模式從類型上來說分為兩種,靜態代理和動態代理。所謂靜態代理,就是在編譯期間就確定的代理關系,一般是一對一的。而動態代理,是一對多的代理關系,是在運行時態才能確定的代理關系。動態代理的原理比較復雜,本篇文章只簡單介紹動態代理的使用,在下一篇文章中,會從原理和代碼的層面,對動態代理做專門的解讀。
案例
靜態代理
背景
以購買火車票為例。乘客(客戶端)在購買火車票的時候,可以在代售點(代理類)進行購買(功能),而不需要花費很長的時間跑去火車站(真實類)進行購買(功能)。
實現
定義抽象接口
public interface shop {void buy();void take(); }定義真實火車站
public class Station implements shop {@Overridepublic void buy() {System.out.println("購買火車票");}@Overridepublic void take() {System.out.println("領取火車票");} }定義代售點
public class ProxyStation implements shop {private Station station = new Station();@Overridepublic void buy() {beforeBuy();station.buy();afterBuy();}private void beforeBuy() {System.out.println("購買之前操作");}private void afterBuy() {System.out.println("購買之后的操作");}@Overridepublic void take() {beforeTake();station.take();afterTake();}private void afterTake() {System.out.println("取票之前的操作");}private void beforeTake() {System.out.println("取票之后的操作");} }驗證程序
public class Test {public static void main(String args[]){ProxyStation proxyStation = new ProxyStation();proxyStation.buy();proxyStation.take();} }運行結果
購買之前操作
購買火車票
購買之后的操作
取票之后的操作
領取火車票
取票之前的操作
Process finished with exit code 0
動態代理
動態代理的場景是一對多的關系,即是一個代理類,多個被代理的類。
在動態代理中,不再關注向客戶端屏蔽原始對象(客戶端可以看到原始對象),而重點是對于一系列的原始實現類,能夠對抽象中的方法進行統一的橫向擴展(方法執行前/后的操作),而不需要為每一個原始實現類都創建一個代理。
動態代理的原理,會在下篇文章中進行分析。
案例
以汽車(抽象)行駛為例子,我們要統計多種車型(原始實現類)通過某段距離的用時。在汽車行駛前,需要進行開始計時的操作(功能擴展)。汽車行駛后,要進行結束計時的操作(功能擴展)。
實現
抽象接口
public interface Moveable {void move() throws Exception;void move_back() throws Exception; }定義實現類
import java.util.Random;public class Car implements Moveable {public void move() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("轎車行駛中…");}public void move_back() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("轎車向后行駛中…");} } import java.util.Random;public class Truck implements Moveable {public void move() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("卡車行駛中…");}public void move_back() throws Exception {Thread.sleep(new Random().nextInt(1000));System.out.println("卡車向后行駛中…");} }定義動態代理工具類
動態代理工具類需要實現InvocationHandler接口,實現invoke方法,通過反射實現對抽象接口方法的調用method.invoke(target, args);。
驗證程序
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy;public class Test {public static void main(String[] args) throws Exception{Car car = new Car();Class<?> cls = car.getClass();InvocationHandler h = new TimeHandler(car);Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);m.move();System.out.println("");m.move_back();System.out.println("");System.out.println("");Truck truck = new Truck();cls = truck.getClass();h = new TimeHandler(truck);m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),cls.getInterfaces(), h);m.move();System.out.println("");m.move_back();System.out.println("");System.out.println("");} }運行結果
汽車開始行駛…
轎車行駛中…
汽車結束行駛…汽車行駛時間:200毫秒!
汽車開始行駛…
轎車向后行駛中…
汽車結束行駛…汽車行駛時間:681毫秒!
汽車開始行駛…
卡車行駛中…
汽車結束行駛…汽車行駛時間:492毫秒!
汽車開始行駛…
卡車向后行駛中…
汽車結束行駛…汽車行駛時間:338毫秒!
Process finished with exit code 0
總結
代理模式優缺點:
- 靜態代理模式:優點是具有較好的擴展性,屏蔽原始實現類;缺點是增加了中間層可能會導致性能下降。
- 動態代理模式:優點是能對多個原始實現類進行統一的功能擴展;缺點是增加了中間層可能會導致性能下降。
代理模式與裝飾器模式的區別:
- 代理模式強調對于訪問的控制,在調用實體類的方法之前或者之后,會添加一些操作,是擴展的廣度。裝飾器模式強調對于方法的加強,擴展的深度。打個比方,張無忌學習乾坤大挪移。裝飾器模式,則增加其深度,從第3層境地學習到第4層境地,注重功能的加強。代理模式則是讓其在學習乾坤大挪移之前,先學習一下九陽神功,兩種武功能夠有所聯系。從外界看來,都是武功的增強,但是一個是深度,一個是廣度。
- 代理模式是代理,裝飾器模式是裝飾,兩者在對原始對象的可見性上是不同的。代理模式中,在客戶看來,無法感知到原始對象,只能接觸代理對象。裝飾器模式中,客戶看來,是能夠感知到原始對象的。
總結
以上是生活随笔為你收集整理的Java设计模式(13)----------代理模式的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Mysql:Mysql数据库系统表之详细
- 下一篇: 数据结构:表达式之中缀转后缀