設計模式:代理、裝飾和介面卡模式的區別

糖拌西红柿發表於2024-07-28

結構對比

講實話,博主當初學習完整設計模式時,這三種設計模式單獨摘哪一種都是十分清晰和明確的,但是隨著模式種類的增加,在實際使用的時候竟然會出現恍惚,例如讀開原始碼時,遇到不以模式命名規範的程式碼時,一時難以說清具體是使用的這三種裡的哪一種。

之所以會出現混淆的原因是,三種模式的實現都是基於面向介面這一思想,三種模式都是針對某一個具體的介面實現,並在其實現類上用一個物件對另一個物件提供間接訪問。

基於混淆點,從類圖上來看,介面卡模式就可以最先被區別出來,介面卡的類結構圖

從類圖上來看,介面卡的主角是Adapter這個類,這個類與目標介面是實現關係,但是Adaptee則不同,它可以是一個介面,也可以是一個具體的類,它是與Target平級的一個物件,與Target毫無關係,而Adapter與它的關係是物件組合,是Adaptee作為Adapter的一個內部成員變數,Adapter的目的是將 Adaptee適配為Target。

相比於介面卡模式,代理模式和裝飾模式反而更容易被混淆, 混淆的原因是二者都是基於一個公共介面,且主角類(Proxy和Decorator)又都是以組合物件的形式,對目標物件(RealSubject和ConcreteComponent)進行二次操作。實現上來看,兩者十分相似。

但是注意,這裡還是有不同,

  • 代理模式是代理物件(Proxy)對實際被代理物件(RealSubject)的間接訪問,是對公共介面的實現類提供間接訪問;
  • 而裝飾模式的裝飾類是對被裝飾介面或者說被裝飾基類(Component)提供間接訪問,不是對介面(Component)的實現類提供間接訪問

也就是說,兩者提供間接訪問的物件不同,一個(代理模式)是基於具體的類,而另一個(裝飾模式)是基於抽象的介面 。這也是為什麼只可以使用一次的request物件要基於裝飾模式提供封裝來達到二次使用的原因(詳細可翻閱設計模式:從HttpServletRequestWrapper瞭解裝飾者模式),基於抽象介面提供的間接訪問是不會破壞具體物件的內容。

本質對比

介面卡模式的本質

介面卡模式的主要功能是進行轉換匹配,目的是複用已有的功能,而不是來實現新的介面。也就是說,客戶端需要的功能應該是已經實現好了的,不需要介面卡模式來實現,介面卡模式主要負責把不相容的介面轉換成客戶端期望的樣子就可以了。

介面卡的本質是轉換功能,以提高複用性。不同於代理和裝飾,介面卡中的目標物件可能與需要適配的物件毫無關係,適配過程中程式碼甚至是全量的重寫,它的目標是將兩個內容沿其中某個為主進行融合。

代理模式的本質

代理模式是透過建立一個代理物件,用這個代理物件去代表真實的物件,客戶端得到這個代理物件後,對客戶端並沒有什麼影響,就跟得到了真實物件一樣來使用。當客戶端操作這個代理物件的時候,實際上功能最終還是會由真實的物件來完成,只不過是透過代理操作的,也就是客戶端操作代理,代理操作真正的物件。
正是因為有代理物件夾在客戶端和被代理的真實物件中間,相當於一箇中轉,那麼在中轉的時候就有很多花招可以玩,比如,判斷一下許可權,如果沒有足夠的許可權那就不進行中轉了,或者中轉到別的操作中。

代理模式的執行邏輯:

代理模式的本質是控制物件訪問。核心在於Proxy角色, 類似於中間商,是目標物件的一個“前沿發言人”,你想要訪問目標物件,或者購買目標廠家的商品,必須從我代理商這裡走, 我甚至可以不建立被代理物件,自己冒充被代理物件(直接以貼牌產品當作目標產品賣你)。

裝飾模式的本質

裝飾模式能夠實現動態地為物件新增功能,是從一個物件外部來給物件增加功能,相當於是改變了物件的外觀。當裝飾過後,從外部使用系統的角度看,就不再是使用原始的那個物件了,而是使用被一系列的裝飾器裝飾過後的物件。這樣就能夠靈活地改變一個物件的功能,只要動態組合的裝飾器發生了改變,那麼最終所得到的物件的功能也就發生了改變。從這一點上來講,代理模式也可以滿足,但是不同的是,裝飾模式這裡有一個代理無法越過的原則,那就是代理模式必須有目標物件,否則裝飾就無從談起。

裝飾模式的本質是透過組合來加強目標物件的能力,是物件能力的延申。裝飾模式是在原有物件的基礎上進行外層包裝,可以對目標物件的每一個方法都進行前置、後置的補充和加強,但是本質上並沒有改變原物件,是一種擴充套件思維,這一點可以參考AOP的思想。

相關文章