1 定義:
1.1 定義:Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.(將物件組合成樹形結構以表示“部分-整體”的層次結構,使得使用者對單個物件和組合物件的使用具有一致性。)
1.2 通用類圖:[透明模式]
1.3 通用程式碼:
public abstract class Component {
// 個體和整體都具有的共享
public void doSomething() {
// 編寫業務邏輯
}
// 增加一個葉子構件或樹枝構件
public abstract void add(Component component);
// 刪除一個葉子構件或樹枝構件
public abstract void remove(Component component);
// 獲得分支下的所有葉子構件和樹枝構件
public abstract ArrayList<Component> getChildren();
}
public class Leaf extends Component {
@Deprecated
public void add(Component component) throws UnsupportedOperationException {
// 空實現,直接拋棄一個“不支援請求”異常
throw new UnsupportedOperationException();
}
@Deprecated
public void remove(Component component)
throws UnsupportedOperationException {
// 空實現
throw new UnsupportedOperationException();
}
@Deprecated
public ArrayList<Component> getChildren()
throws UnsupportedOperationException {
// 空實現
throw new UnsupportedOperationException();
}
public void doSomething() {
System.out.println("我是一片葉!");
}
}
public class Composite extends Component {
// 構件容器
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
// 增加一個葉子構件或樹枝構件
public void add(Component component) {
this.componentArrayList.add(component);
}
// 刪除一個葉子構件或樹枝構件
public void remove(Component component) {
this.componentArrayList.remove(component);
}
// 獲得分支下的所有葉子構件和樹枝構件
public ArrayList<Component> getChildren() {
return this.componentArrayList;
}
public void doSomething() {
System.out.println("我是一樹枝!");
}
}
public class Client {
public static void main(String[] args) {
// 建立一個根節點
Component root = new Composite();
// 建立一個樹枝構件
Component branch = new Composite();
// 建立一個葉子節點
Component leaf = new Leaf();
// 建立整體
root.add(branch);
branch.add(leaf);
display(root);
}
// 通過遞迴遍歷樹
public static void display(Component root) {
root.doSomething();
for (Component c : root.getChildren()) {
if (c instanceof Leaf) { // 葉子節點/////////////////////
c.doSomething();
} else { // 樹枝節點
display(c);
}
}
}
}
2 優點
2.1 高層模組呼叫簡單:樹形機構中所有節點都是Component,高層模組不必關心自己處理的是單個物件還是整個組合結構,簡化了高層模組的程式碼;
2.2 節點自由增加:容易擴充套件,符合OCP,對維護有利。
3 缺點
3.1 在上述遍歷樹時,需要判斷是葉子還是樹枝,這點若直接通過型別判斷,則會形成“對實現類的依賴”與依賴倒置原則衝突。不過似乎可以通過在Component中新增標識,在子類中實現它。
4 應用場景
4.1 維護和展示部分-整體關係的場景,如樹形選單、檔案和資料夾管理;
4.2 從一個整體中能夠獨立出部分模組或功能的場景;
4.3 家族關係圖譜(倒推方可)
5 注意事項
暫無
6 擴充套件
6.1 組合模式的真實引用:依靠關聯式資料庫的非物件儲存效能,儲存樹形結構。
6.2 安全的組合模式:類圖如下,這種做法將樹枝與葉子完全分開,在遍歷時需要強制型別轉換(因而破壞了依賴倒置原則),也需要型別判斷。可以避免執行間異常。
6.3 組合模式的遍歷:給定一個結點,查詢其父結點。
7 範例
(如上6.3,樹遍歷查詢)
原始碼如下:(作者原書例)
public abstract class Corp {
// 公司每個人都有名稱
private String name = "";
// 公司每個人都職位
private String position = "";
// 公司每個人都有薪水
private int salary = 0;
// 父節點是誰
private Corp parent = null;
/*
* 通過介面的方式傳遞,我們改變一下習慣,傳遞進來的引數名以下劃線開始 這個在一些開源專案中非常常見,一般建構函式都是定義的
*/
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;
}
// 設定父節點
protected void setParent(Corp _parent) {
this.parent = _parent;
}
// 等到父節點
public Corp getParent() {
return this.parent;
}
}
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) {
corp.setParent(this); // 設定父節點
this.subordinateList.add(corp);
}
// 我有哪些下屬
public ArrayList<Corp> getSubordinate() {
return this.subordinateList;
}
}
public class Leaf extends Corp {
// 就寫一個建構函式,這個是必須的
public Leaf(String _name, String _position, int _salary) {
super(_name, _position, _salary);
}
}
public class Client {
static Leaf f;
public static void main(String[] args) {
// 首先是組裝一個組織結構出來
Branch ceo = compositeCorpTree();
// 首先把CEO的資訊列印出來:
System.out.println(ceo.getInfo());
System.out.println();
System.out.println("開發人員 f 的上司是:" + f.getParent().getInfo());
System.out.println();
// 然後是所有員工資訊
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);
// 把所有的小兵都產生出來
Leaf a = new Leaf("a", "開發人員", 2000);
Leaf b = new Leaf("b", "開發人員", 2000);
Leaf c = new Leaf("c", "開發人員", 2000);
Leaf d = new Leaf("d", "開發人員", 2000);
Leaf e = new Leaf("e", "開發人員", 2000);
f = new Leaf("f", "開發人員", 2000);
Leaf g = new Leaf("g", "開發人員", 2000);
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);
Leaf zhengLaoLiu = new Leaf("鄭老六", "研發部副經理", 20000);
// 開始組裝
// CEO下有三個部門經理和一個祕書
root.addSubordinate(k);
root.addSubordinate(developDep);
root.addSubordinate(salesDep);
root.addSubordinate(financeDep);
// 研發部經理
developDep.addSubordinate(zhengLaoLiu);
developDep.addSubordinate(firstDevGroup);
developDep.addSubordinate(secondDevGroup);
// 看看開發兩個開發小組下有什麼
firstDevGroup.addSubordinate(a);
firstDevGroup.addSubordinate(b);
firstDevGroup.addSubordinate(c);
secondDevGroup.addSubordinate(d);
secondDevGroup.addSubordinate(e);
secondDevGroup.addSubordinate(f);
// 再看銷售部下的人員情況
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
開發人員 f 的上司是:姓名:吳大棒槌 職位:開發二組組長 薪水:6000
姓名:k 職位:CEO祕書 薪水:8000
姓名:劉大瘸子 職位:研發部門經理 薪水:10000
姓名:鄭老六 職位:研發部副經理 薪水:20000
姓名:楊三乜斜 職位:開發一組組長 薪水:5000
姓名:a 職位:開發人員 薪水:2000
姓名:b 職位:開發人員 薪水:2000
姓名:c 職位:開發人員 薪水:2000
姓名:吳大棒槌 職位:開發二組組長 薪水:6000
姓名:d 職位:開發人員 薪水:2000
姓名:e 職位:開發人員 薪水:2000
姓名:f 職位:開發人員 薪水:2000
姓名:馬二柺子 職位:銷售部門經理 薪水:20000
姓名:h 職位:銷售人員 薪水:5000
姓名:i 職位:銷售人員 薪水:4000
姓名:趙三駝子 職位:財務部經理 薪水:30000
姓名:j 職位:財務人員 薪水:5000
轉自:http://blog.csdn.net/yuanlong_zheng/article/details/7584797