結構型設計模式

月亮熊發表於2024-06-24

介面卡模式

需求方法M1。但已經存在一個方法M2能實現需求功能,引入子類來覆蓋M1方法(M1方法中呼叫已有的M2方法)。這個新子類就是介面卡

將已有的方法轉換為需求的另一種方法(一般由於方法名差異;引數不同)

這一模式中的“介面”是廣義介面,可代指一個/一組方法集合

優點:無需修改已有內容,開閉;增加了透明性,使用者複用性;可擴充套件性非常好

1. 類介面卡

如何不修改已有結構的前提下,讓使用者透過目標類的方法R1,呼叫到已有類的方法R2?
引入子類,繼承目標類,在覆蓋目標類方法的時候去呼叫繼承已有類/適配者的方法R2(里氏替換,子蓋父)
同時作為目標類,已有類的子類
(缺點:JAVA不能多重繼承,因此target類是一個介面就可以,具體/抽象類不行。介面模組有標記)

2. 物件介面卡

介面卡和目標抽象類仍然是繼承關係,但是介面卡和已有類是關聯關係
(優勢:規避目標類為具體類/抽象類;已有類存在多個,受限多重繼承)
介面卡中呼叫多個已有類內部的方法,多個已有類作為介面卡物件

介面卡可以放入配置檔案,用反射機制生成具體介面卡物件(符合開閉原則)

(關聯關係-----一個類的物件定義為另一個類成員變數
介面可以繼承介面,而類只能實現介面。)
(抽象類也可以包含具體方法)

橋接模式bridge

(類的多繼承關係/蠟筆重構為關聯關係/毛筆)
將不同的變化原因/維度做成獨立的整合結構,提高了可擴充套件性,符合開閉

將抽象部分與實現部分分離,使其獨立變化

具備公共的方法,放入抽象維度--抽象類/擴充抽象類;

抽象關聯取代了傳統的多層繼承

橋接,將一個右邊的子類顏色注入左邊,在左邊子類呼叫左父類注入的顏色

類之間的靜態繼承關係轉換為動態的物件組合關係

從兩個維度各選一個子類,放到客戶端。二者都可以獨立擴充套件修改

橋接模式實現

聚合關係

缺陷:

關聯關係在抽象層,難以理解;正確識別兩個獨立變化維度較困難

組合模式(Composite Pattern)

組合模式依據樹形結構來組合物件,用來表示部分以及整體層次
組合模式包含如下角色:

Component:抽象構件
抽象構件可以是介面或者抽象類,為葉子構件和容器構件物件宣告介面,在該角色中可以包含所有子類共有行為的宣告和實現。在抽象構件中定義了訪問及管理它的子結構的方法,如增加子構件、刪除子構件、獲取子構件等。
Leaf:葉子構件
葉子構件在組合結構中表示葉子節點物件,葉子節點沒有子節點,它實現了在抽象構件中定義的行為。對於那些訪問及管理子構件的方法,可以透過異常等方式進行處理。
Composite:容器構件
容器構件在組合結構中表示容器節點物件,容器節點包含子節點,其子節點可以是葉子節點,也可以是容器節點,它提供了一個集合用於儲存子節點,實現了在抽象構件中定義的行為,包括那些訪問及管理子構件的方法,在其業務方法中可以遞迴呼叫其子節點的業務方法。
Client:客戶類
客戶類是可以透過抽象構件介面訪問和控制組合構件中的物件

組合模式的優點:

可以清楚地定義分層次的複雜物件,表示物件的全部或部分層次,使得增加新構件也更容易。
客戶端呼叫簡單,客戶端可以一致的使用組合結構或其中單個物件。
定義了包含葉子物件和容器物件的類層次結構,葉子物件可以被組合成更復雜的容器物件,而這個容器物件又可以被組合,這樣不斷遞迴下去,可以形成複雜的樹形結構。
更容易在組合體內加入物件構件,客戶端不必因為加入了新的物件構件而更改原有程式碼。

組合模式的缺點:

使設計變得更加抽象,物件的業務規則如果很複雜,則實現組合模式具有很大挑戰性,而且不是所有的方法都與葉子物件子類都有關聯。
增加新構件時可能會產生一些問題,很難對容器中的構件型別進行限制。

組合模式的適用環境:

需要表示一個物件整體或部分層次,在具有整體和部分的層次結構中,希望透過一種方式忽略整體與部分的差異,可以一致地對待它們。
讓客戶能夠忽略不同物件層次的變化,客戶端可以針對抽象構件程式設計,無須關心物件層次結構的細節。
物件的結構是動態的並且複雜程度不一樣,但客戶需要一致地處理它們。

透明的組合模式
在透明組合模式中,抽象構件Component中宣告瞭所有用於管理成員物件的方法,包括add、remove、getChild等方法,這樣做的好處是確保所有的構件類都有相同的介面。在客戶端看來,葉子物件與容器物件所提供的方法是一致的,客戶端可以相同的對待所有物件。

安全的組合模式
在安全組合模式中,在抽象構件Component中沒有宣告任何用於管理成員物件的方法,而是在Composite類中宣告這些用於管理成員物件的方法。這種做法是安全的,因為根本不想葉子物件提供這些管理成員物件的方法,對於葉子物件,客戶端不可能呼叫到這些方法。

優點
程式碼複用性:組合模式促進了程式碼的重用,因為它透過將相似的操作應用於樹中的所有節點,從而減少了重複的程式碼。這使得在系統中使用組合模式時,可以更好地利用已有的程式碼,並且可以避免在多個地方編寫相似的邏輯
核心是能夠靈活且安全地處理多層巢狀的結構。透過組合模式,你可以輕鬆地構建出多層次的樹形結構,並且可以統一對待樹中的各個節點,無論是葉子節點還是組合節點。

裝飾模式DECORATOR

想要更加靈活的替代繼承關係,引入這一物件導向設計

動態的設計

一致性的/透明的修改==對共同父類修改

裝飾模式需要涉及到以下幾個角色:

抽象元件(Component):定義一個系列物件應該有的功能,今後的擴充套件呼叫均基於該介面實現
具體元件(SpecificComponent):抽象元件的具體實現,裝飾類將對該具體實現進行擴充套件
抽象裝飾類(Decorator):裝飾類將透過繼承該類來進行功能擴充套件,並且在該類中包含具體元件例項
具體裝飾類(DecorateComponent):實現抽象裝飾類的具體裝飾類,用於對抽象裝飾類中的具體元件功能呼叫的擴充套件

透明裝飾模式和半透明裝飾模式

透明裝飾模式
在透明裝飾模式中要求客戶端完全針對抽象程式設計,裝飾模式的透明性要求客戶端程式不應該將物件宣告為具體構件型別或具體裝飾型別,而應該全部宣告為抽象構件型別。對客戶端而言,具體構件類和具體裝飾類物件沒有任何區別。(缺點,無法單獨呼叫裝飾類的獨有功能)

//不應該將物件宣告為具體構件型別或具體裝飾者型別
Window window=new Window();
//應該宣告為抽象構件型別,向上轉型
Component window=new Window();

半透明裝飾模式
用具體裝飾型別來定義裝飾後的物件,而具體構件型別仍然可以使用抽象構件型別來定義,可以單獨呼叫裝飾的獨有方法。(缺點:無法多次進行裝飾)

//具體構件型別仍然可以使用抽象構件型別來定義
Component window =new Window();
//具體裝飾型別來定義裝飾後的物件
BlackBorderDec blackBorder=new BlackBorderDec(window);
//可以單獨呼叫
blackBorder.setBlackBorder();

外觀模式(Facade Pattern)

外部與子系統的通訊透過一個統一的外觀物件進行,為子系統中的一組介面提供一個統一的入口。外觀模式定義了一個高層介面,這個介面使得子系統更加容易使用。

代理模式-proxy pattern

間接訪問,對某物件訪問的限制。(限制訪客,保護其安全性)
可以在不修改目標物件程式碼的基礎上,增強額外的功能操作,即擴充套件目標物件的功能

(其中prerequest方法是類似建立連結,寫系統日誌等前期準備;postrequest方法為連結結束後的一系列方法)

    1. 虛擬代理,這種方式通常用於要建立的目標物件開銷很大時。例如,下載一幅很大的影像需要很長時間,這時可以先用小比例的虛擬代理替換真實的物件,消除使用者對伺服器慢的感覺。
    1. 遠端代理:最經典的代理模式之一,遠端代理負責與遠端JVM通訊,以實現本地呼叫者與遠端被呼叫者之間的正常互動
    1. 保護代理,當對目標物件訪問需要某種許可權時,提供對目標物件的受控保護,拒絕服務許可權不夠的客戶。
    1. 緩衝代理:本地快取以前訪問的物件,下次訪問呼叫
    1. 智慧指引代理:主要用於呼叫目標物件時,附加一些額外的處理功能。例如,增加計算真實物件的引用次數的功能,這樣當該物件沒有被引用時,就可以自動釋放它(C++智慧指標)

相關文章