1. 程式人生 > 實用技巧 >安裝Harbor並修改預設使用的80埠

安裝Harbor並修改預設使用的80埠

組合模式(Composite Pattern)是一種結構型設計模式, 你可以使用它將物件組合成樹狀結構, 並且能像使用獨立物件一樣使用它們。組合模式建立了一個包含自己物件組的類。該類提供了修改相同物件組的方式。

組合模式 問題引入

如果應用的核心模型能用樹狀結構表示, 在應用中使用組合模式才有價值。

例如, 你有兩類物件:產品盒子。 一個盒子中可以包含多個 產品或者幾個較小的 盒子 。 這些小 盒子中同樣可以包含一些 產品或更小的 盒子 , 以此類推。

假設你希望在這些類的基礎上開發一個定購系統。 訂單中可以包含無包裝的簡單產品, 也可以包含裝滿產品的盒子……以及其他盒子。 此時你會如何計算每張訂單的總價格呢?

你可以嘗試直接計算: 開啟所有盒子, 找到每件產品, 然後計算總價。 這在真實世界中或許可行, 但在程式中, 你並不能簡單地使用迴圈語句來完成該工作。 你必須事先知道所有產品盒子的類別, 所有盒子的巢狀層數以及其他繁雜的細節資訊。 因此, 直接計算極不方便, 甚至完全不可行。

組合模式 解決方案

組合模式建議使用一個通用介面來與產品盒子進行互動, 並且在該介面中宣告一個計算總價的方法。

那麼方法該如何設計呢? 對於一個產品, 該方法直接返回其價格; 對於一個盒子, 該方法遍歷盒子中的所有專案, 詢問每個專案的價格, 然後返回該盒子的總價格。 如果其中某個專案是小一號的盒子, 那麼當前盒子也會遍歷其中的所有專案, 以此類推, 直到計算出所有內部組成部分的價格。 你甚至可以在盒子的最終價格中增加額外費用, 作為該盒子的包裝費用。

該方式的最大優點在於你無需瞭解構成樹狀結構的物件的具體類。 你也無需瞭解物件是簡單的產品還是複雜的盒子。 你只需呼叫通用介面以相同的方式對其進行處理即可。 當你呼叫該方法後, 物件會將請求沿著樹結構傳遞下去。

真實世界類比

大部分國家的軍隊都採用層次結構管理。 每支部隊包括幾個師, 師由旅構成, 旅由團構成, 團可以繼續劃分為排。 最後, 每個排由一小隊實實在在的士兵組成。 軍事命令由最高層下達, 通過每個層級傳遞, 直到每位士兵都知道自己應該服從的命令。

組合模式 結構

  1. 元件 (Component) 介面描述了樹中簡單專案和複雜專案所共有的操作。

  2. 葉節點 (Leaf) 是樹的基本結構, 它不包含子專案。
    一般情況下, 葉節點最終會完成大部分的實際工作, 因為它們無法將工作指派給其他部分。

  3. 容器 (Container)——又名 “組合 (Composite)”——是包含葉節點或其他容器等子專案的單位。 容器不知道其子專案所屬的具體類, 它只通過通用的元件介面與其子專案互動。

    容器接收到請求後會將工作分配給自己的子專案, 處理中間結果, 然後將最終結果返回給客戶端。

  4. 客戶端 (Client) 通過元件介面與所有專案互動。 因此, 客戶端能以相同方式與樹狀結構中的簡單或複雜專案互動。

組合模式 虛擬碼

在本例中, 我們將藉助組合模式幫助你在圖形編輯器中實現一系列的幾何圖形。

組合圖形Compoundraphic是一個容器, 它可以由多個包括容器在內的子圖形構成。 組合圖形與簡單圖形擁有相同的方法。 但是, 組合圖形自身並不完成具體工作, 而是將請求遞迴地傳遞給自己的子專案, 然後 “彙總” 結果。

通過所有圖形類所共有的介面, 客戶端程式碼可以與所有圖形互動。 因此, 客戶端不知道與其互動的是簡單圖形還是組合圖形。 客戶端可以與非常複雜的物件結構進行互動, 而無需與組成該結構的實體類緊密耦合。

 1 // 元件介面會宣告組合中簡單和複雜物件的通用操作。
 2 interface Graphic is
 3     method move(x, y)
 4     method draw()
 5 
 6 // 葉節點類代表組合的終端物件。葉節點物件中不能包含任何子物件。葉節點物件
 7 // 通常會完成實際的工作,組合物件則僅會將工作委派給自己的子部件。
 8 class Dot implements Graphic is
 9     field x, y
10 
11     constructor Dot(x, y) { ... }
12 
13     method move(x, y) is
14         this.x += x, this.y += y
15 
16     method draw() is
17         // 在座標位置(X,Y)處繪製一個點。
18 
19 // 所有元件類都可以擴充套件其他元件。
20 class Circle extends Dot is
21     field radius
22 
23     constructor Circle(x, y, radius) { ... }
24 
25     method draw() is
26         // 在座標位置(X,Y)處繪製一個半徑為 R 的圓。
27 
28 // 組合類表示可能包含子專案的複雜元件。組合物件通常會將實際工作委派給子項
29 // 目,然後“彙總”結果。
30 class CompoundGraphic implements Graphic is
31     field children: array of Graphic
32 
33     // 組合物件可在其專案列表中新增或移除其他元件(簡單的或複雜的皆可)。
34     method add(child: Graphic) is
35         // 在子專案陣列中新增一個子專案。
36 
37     method remove(child: Graphic) is
38         // 從子專案陣列中移除一個子專案。
39 
40     method move(x, y) is
41         foreach (child in children) do
42             child.move(x, y)
43 
44     // 組合會以特定的方式執行其主要邏輯。它會遞迴遍歷所有子專案,並收集和
45     // 彙總其結果。由於組合的子專案也會將呼叫傳遞給自己的子專案,以此類推,
46     // 最後組合將會完成整個物件樹的遍歷工作。
47     method draw() is
48         // 1. 對於每個子部件:
49         //     - 繪製該部件。
50         //     - 更新邊框座標。
51         // 2. 根據邊框座標繪製一個虛線長方形。
52 
53 
54 // 客戶端程式碼會通過基礎介面與所有元件進行互動。這樣一來,客戶端程式碼便可同
55 // 時支援簡單葉節點元件和複雜元件。
56 class ImageEditor is
57     method load() is
58         all = new CompoundGraphic()
59         all.add(new Dot(1, 2))
60         all.add(new Circle(5, 3, 10))
61         // ...
62 
63     // 將所需元件組合為複雜的組合元件。
64     method groupSelected(components: array of Graphic) is
65         group = new CompoundGraphic()
66         group.add(components)
67         all.remove(components)
68         all.add(group)
69         // 所有元件都將被繪製。
70         all.draw()

組合模式 適用場景

如果你需要實現樹狀物件結構, 可以使用組合模式。

組合模式為你提供了兩種共享公共介面的基本元素型別: 簡單葉節點和複雜容器。 容器中可以包含葉節點和其他容器。 這使得你可以構建樹狀巢狀遞迴物件結構。

如果你希望客戶端程式碼以相同方式處理簡單和複雜元素, 可以使用該模式。

組合模式中定義的所有元素共用同一個介面。 在這一介面的幫助下, 客戶端不必在意其所使用的物件的具體類。

組合模式 實現方式

  1. 用的核心模型能夠以樹狀結構表示。 嘗試將其分解為簡單元素和容器。 記住, 容器必須能夠同時包含簡單元素和其他容器。

  2. 定義介面及其一系列方法, 這些方法對簡單和複雜元素都有意義。

  3. 個葉節點類表示簡單元素。 程式中可以有多個不同的葉節點類。

  4. 容器類表示複雜元素。 在該類中, 建立一個數組成員變數來儲存對於其子元素的引用。 該陣列必須能夠同時儲存葉節點和容器, 因此請確保將其宣告為組合介面型別。

    件介面方法時, 記住容器應該將大部分工作交給其子元素來完成。

  5. 在容器中定義新增和刪除子元素的方法。

記住, 這些操作可在元件介面中宣告。 這將會違反介面隔離原則, 因為葉節點類中的這些方法為空。 但是, 這可以讓客戶端無差別地訪問所有元素, 即使是組成樹狀結構的元素。

組合模式 優缺點

組合模式 優點

  • 你可以利用多型和遞迴機制更方便地使用複雜樹結構。

  • 開閉原則。 無需更改現有程式碼, 你就可以在應用中新增新元素, 使其成為物件樹的一部分。

組合模式 缺點

  • 對於功能差異較大的類, 提供公共介面或許會有困難。 在特定情況下, 你需要過度一般化元件介面, 使其變得令人難以理解。

組合模式 與其他模式的關係

  • 橋接模式、 狀態模式和策略模式 (在某種程度上包括介面卡模式) 模式的介面非常相似。 實際上, 它們都基於組合模式——即將工作委派給其他物件, 不過也各自解決了不同的問題。 模式並不只是以特定方式組織程式碼的配方, 你還可以使用它們來和其他開發者討論模式所解決的問題。

  • 你可以在建立複雜組合樹時使用生成器模式, 因為這可使其構造步驟以遞迴的方式執行。

  • 責任鏈模式通常和組合模式結合使用。 在這種情況下, 葉元件接收到請求後, 可以將請求沿包含全體父元件的鏈一直傳遞至物件樹的底部。

  • 你可以使用迭代器模式來遍歷組合樹。

  • 你可以使用訪問者模式對整個組合樹執行操作。

  • 你可以使用享元模式實現組合樹的共享葉節點以節省記憶體。

  • 組合和裝飾模式的結構圖很相似, 因為兩者都依賴遞迴組合來組織無限數量的物件。

    裝飾類似於組合, 但其只有一個子元件。 此外還有一個明顯不同: 裝飾為被封裝物件添加了額外的職責, 組合僅對其子節點的結果進行了 “求和”。

    但是, 模式也可以相互合作: 你可以使用裝飾來擴充套件組合樹中特定物件的行為。

  • 大量使用組合和裝飾的設計通常可從對於原型模式的使用中獲益。 你可以通過該模式來複制複雜結構, 而非從零開始重新構造。

轉載 https://geek-docs.com/design-pattern/composite-pattern/composite-pattern-index.html