我學設計模式 之 合成模式
我學設計模式之合成模式
1. 簡介
合成模式屬於物件的結構模式,有時又叫做 部分 – 整體模式。合成模式將物件組織到樹結構中,可以用來描述整體與部分的關係。
合成模式把部分和整體的關係用樹結構表示出來。合成模式使得客戶端把一個個單獨的成分物件和有他們複合而成的合成物件同等看待。
2. 組合模式的結構
先給出合成模式的簡單類圖如下:
從類圖中可以看出合成模式涉及3個角色:
抽象構件角色(Component):這是一個抽象角色,他給參加組合的物件規定一個介面,這個角色給出共有的介面及其預設行為。
樹葉構件角色(Leaf):代表參加組合的樹葉物件。一個樹葉沒有下級的子物件。定義出參加原始物件的行為。
樹枝構件角色(Composite):代表參加組合的有子物件的物件,並給出樹枝構件物件的行為。
3. 安全和透明式的合成模式
合成模式的實現根據實現介面的區別分為兩種形式,分別為安全式和透明式。他們的類圖分別如下:
透明方式:就是在Component裡面宣告所有的用來管理子物件的方法,包括add()、remove()以及getChild()方法,這樣做的好處是所有的構件類都有相同的介面。在客戶端看來,樹葉類物件與合成類物件的區別起碼在介面層次上消失了,客戶端可以同等的對待所有的物件。這就是透明形式的合成模式。
這個選擇的缺點是不夠安全的,因為樹葉類物件和合成類物件在本質上是有區別的,樹葉類物件不可能有一層的物件,因此add()、remove()以及getChild()方法沒有意義,但是在編譯時期不會出錯,而只會在執行時期才會出錯。
安全方式:是在Composite類裡面宣告所有的用來管理子類物件的方法。這樣的做法是安全的做法,因為樹葉型別的物件根本就沒有管理子物件的方法。因此,如果客戶端對樹葉物件使用這些方法時會在編譯時期出錯。編譯不通過,就不會出現執行時出錯。
這個選擇的缺點是不夠透明,因為樹葉類和合成類將具有不同的介面。
4. 組合模式的用法
在這裡使用組合模式對公司人事管理的樹狀機構進行描述:
首先建立抽象構建,原始碼如下:
package com.zsw.composite;
public abstract class Corp {
private String name; //名稱 private String position; //職位 private int salary = 0; //薪水
public Corp(String name,String position,int salary){ this.name = name; this.position = position; this.salary = salary; }
public String getInfo(){ String info = ""; info = "姓名:" + this.name; info = info + "/t職位:" + this.position; info = info + "/t薪水: " + this.salary; return info; } } |
建立樹葉構件原始碼如下:
package com.zsw.composite;
public class Leaf extends Corp {
public Leaf(String name, String position, int salary) { super(name, position, salary); } } |
建立樹枝構件原始碼如下:
package com.zsw.composite; import java.util.ArrayList; public class Branch extends Corp {
ArrayList<Corp> subordinateList = new ArrayList<Corp>();
public Branch(String name, String position, int salary) { super(name, position, salary); }
public void addSubordinate(Corp corp){ this.subordinateList.add(corp); }
public ArrayList<Corp> getSubordinate(){ return this.subordinateList; } }
|
客戶端原始碼如下:
package com.zsw.composite; import java.util.ArrayList; public class Client {
public static void main(String[] args) { Branch ceo = compositeCorpTree(); System.out.println(ceo.getInfo()); System.out.println(getTreeInfo(ceo)); }
//把整個樹組裝出來 public static Branch compositeCorpTree(){ //總經理CEO Branch root = new Branch("王大","總經理",100000);
//三個部門經理 Branch developDep = new Branch("劉大","研發部門經理",10000); Branch salesDep = new Branch("劉大","銷售部門經理",20000); Branch financeDep = new Branch("劉大","財務部門經理",30000);
//二個小組長 Branch firstDevGroup = new Branch("楊三","開發一組組長",5000); Branch secondDevGroup = new Branch("吳大","開發二組組長",6000); Branch zhengLaoLiu = new Branch("鄭成功","研發部副經理",20000);
//建立所有小兵 Leaf a = new Leaf("a","開發人員",3000); Leaf b = new Leaf("b","開發人員",3000); Leaf c = new Leaf("c","開發人員",3000); Leaf d = new Leaf("d","開發人員",3000); Leaf e = new Leaf("e","開發人員",3000); Leaf f = new Leaf("f","開發人員",3000); Leaf g = new Leaf("g","開發人員",3000);
Leaf h = new Leaf("h","銷售人員",5000); Leaf i = new Leaf("i","銷售人員",4000); Leaf j = new Leaf("j","財務人員",5000); Leaf k = new Leaf("k","CEO祕書",8000);
//開始組裝 //CEO下有三個部門經理和一個祕書 root.addSubordinate(k); root.addSubordinate(developDep); root.addSubordinate(salesDep); root.addSubordinate(financeDep);
//研發部經理 developDep.addSubordinate(zhengLaoLiu); developDep.addSubordinate(firstDevGroup); developDep.addSubordinate(secondDevGroup);
//2個小組 firstDevGroup.addSubordinate(a); firstDevGroup.addSubordinate(b); firstDevGroup.addSubordinate(c); firstDevGroup.addSubordinate(d); secondDevGroup.addSubordinate(e); secondDevGroup.addSubordinate(f); secondDevGroup.addSubordinate(g);
//銷售部門下人員情況 salesDep.addSubordinate(h); salesDep.addSubordinate(i);
//財務 financeDep.addSubordinate(j);
return root; }
//遍歷整棵樹,只要給我根節點,我就能遍歷出所有的節點 public static String getTreeInfo(Branch root){ ArrayList<Corp> subordinateList = root.getSubordinate(); String info = "";
for(Corp s : subordinateList){ if(s instanceof Leaf){ info = info + s.getInfo() + "/n"; }else{ info = info + s.getInfo() + "/n" + getTreeInfo((Branch)s); } } return info; } }
|
顯示結果如下:
姓名:王大 職位:總經理 薪水: 100000 姓名:k 職位:CEO祕書 薪水: 8000 姓名:劉大 職位:研發部門經理 薪水: 10000 姓名:鄭成功 職位:研發部副經理 薪水: 20000 姓名:楊三 職位:開發一組組長 薪水: 5000 姓名:a 職位:開發人員 薪水: 3000 姓名:b 職位:開發人員 薪水: 3000 姓名:c 職位:開發人員 薪水: 3000 姓名:d 職位:開發人員 薪水: 3000 姓名:吳大 職位:開發二組組長 薪水: 6000 姓名:e 職位:開發人員 薪水: 3000 姓名:f 職位:開發人員 薪水: 3000 姓名:g 職位:開發人員 薪水: 3000 姓名:劉大 職位:銷售部門經理 薪水: 20000 姓名:h 職位:銷售人員 薪水: 5000 姓名:i 職位:銷售人員 薪水: 4000 姓名:劉大 職位:財務部門經理 薪水: 30000 姓名:j 職位:財務人員 薪水: 5000 |
5. 組合模式的應用場景
a) 一個檔案系統就是一個典型的合成模式系統。可以把目錄和檔案同等對待和處理,這也就是合成模式的應用。
b) 道士的故事,哄小孩睡覺講故事,從前有座山、山裡有個廟、廟裡有個老道,老道講了一個故事,故事說從前有座山、山裡有個廟…..這樣迴圈下去直到小孩睡著。在這個故事中有兩種角色:一種沒有內部角色,例如山、廟、道士;另一種是有內部角色的的角色,在這個故事中的故事。故事裡又有、山、廟、道士….此故事的UML類圖如下:
c) 公司的人事管理就是一個典型的樹狀結構,公司的結構如下圖所示,從最高的老大,往下一層的管理,最後到我們這層小兵,很典型的樹狀結構。
d) ASP.NET的TreeView控制元件既是典型的組合模式應用,所有WEB控制元件的基類都是System.Web.UI.Control,而Control基類中就有Add和Remove方法,這就是典型的組合模式的應用。
e) 比如現在頁面結構一般都是上下結構,上放系統的Logo,下邊分為兩部分:左邊是導航選單,右邊是展示區,左邊的導航選單一般都是樹形結構,比較清晰.
f) AWT庫中的例子,AWT和Swing中的圖形介面構件是建立在AWT庫中的Container類和Component類上的。其中Button和CheckBox是樹葉形的構件,而Container則是樹枝行的構件。如AWT合成模式的UML類圖:
在Container類中,有操作聚集的對應的方法,而在Component類中沒有這樣的方法。這就是說AWT總使用的合成模式是安全形式的合成模式。
g) 需要描述物件的部分和整體的等級結構。
h) 需要客戶端忽略掉個體構件和組合構件的區別。客戶端必須平等對待所有的構件,包括個體元件和組合構件。
i) 合成模式可以很容易的增加新種類的構件。
j) 使用合成模式可以是客戶端變得很容易設計,因為客戶端不需要知道構件時樹葉構件還是樹枝構件。
6. 組合模式的優缺點
優點:
缺點:
ü 使用合成模式後,控制樹枝構件的型別就不太容易。
ü 用繼承的方法增加新的行為很困難。
7. 參考文件
a) 《Java與模式》
b) 《大話設計模式》
相關文章
- 我學設計模式 之 代理模式設計模式
- 我學設計模式 之 策略模式設計模式
- 我學設計模式 之 命令模式設計模式
- 我學設計模式 之 中介模式設計模式
- 我學設計模式 之 模板模式設計模式
- 我學設計模式 之 單例模式設計模式單例
- 我學設計模式 之 門面模式設計模式
- 我學設計模式 之 橋接模式設計模式橋接
- 我學設計模式 之 狀態模式設計模式
- 我學設計模式 之 建造模式設計模式
- 我學設計模式 之 享元模式設計模式
- 我學設計模式 之 備忘模式設計模式
- 我學設計模式 之裝飾模式設計模式
- 我學設計模式 之 原型模型模式設計模式原型模型
- 我學設計模式 之 物件導向設計原則設計模式物件
- 我該學設計模式嗎?設計模式
- 設計模式學習之單例模式設計模式單例
- 設計模式學習之訪問者模式設計模式
- 設計模式學習筆記之策略模式設計模式筆記
- JavaScript設計模式學習之單例模式JavaScript設計模式單例
- 跟著GPT學設計模式之代理模式GPT設計模式
- 小學生學習設計模式之單例模式設計模式單例
- 設計模式之代理模式設計模式
- 設計模式之Plugin模式設計模式Plugin
- 設計模式之策略模式設計模式
- 《設計模式》之代理模式設計模式
- 設計模式之命令模式設計模式
- 設計模式之【策略模式】設計模式
- 【設計模式之代理模式】設計模式
- 【設計模式之策略模式】設計模式
- 設計模式學習筆記之工廠模式設計模式筆記
- 每天學點設計模式之---介面卡模式設計模式
- 設計模式學習筆記之迭代器模式設計模式筆記
- 設計模式學習筆記之狀態模式設計模式筆記
- 設計模式學習筆記之單例模式設計模式筆記單例
- 跟著GPT學設計模式之橋接模式GPT設計模式橋接
- 設計模式之單例設計模式設計模式單例
- 我的Java設計模式-代理模式Java設計模式