將對象組合成樹形結構以表示「部分-總體」的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。安全
/** * 組合對象 * Created by callmeDevil on 2019/8/11. */ public abstract class Component { protected String name; public Component(String name){ this.name = name; } // 一般都用add 和remove 方法來提供增長或移除樹葉或樹枝的功能 public abstract void add(Component c); public abstract void remove(Component c); public abstract void dispaly(int depth); }
/** * 枝節點行爲,用來存儲子部件 * Created by callmeDevil on 2019/8/11. */ public class Composite extends Component{ // 一個子對象集合用來存儲其下屬枝節點和葉節點 private List<Component> children = new ArrayList<>(); public Composite(String name){ super(name); } @Override public void add(Component c) { children.add(c); } @Override public void remove(Component c) { children.remove(c); } @Override public void dispaly(int depth) { StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } // 顯示枝節點名稱,並對其下級進行遍歷 System.out.println(String.format("%s %s", sb.toString(), name)); for (Component child : children) { child.dispaly(depth + 3); } } }
/** * 葉節點對象 * Created by callmeDevil on 2019/8/11. */ public class Leaf extends Component { public Leaf(String name) { super(name); } @Override public void add(Component c) { System.out.println("cannot add to a leaf"); } @Override public void remove(Component c) { System.out.println("cannot remove from a leaf"); } @Override public void dispaly(int depth) { StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } // 顯示名稱和級別 System.out.println(String.format("%s %s", sb.toString(), name)); } }
public class Test { public static void main(String[] args) { // 生成樹根root,根上長出兩葉LeafA 和LeafB Composite root = new Composite("root"); root.add(new Leaf("Leaf A")); root.add(new Leaf("Leaf B")); // 根上長出分枝 Composite X ,分枝上也有兩葉LeafXA 和LeafXB Composite comp = new Composite("Composite X"); comp.add(new Leaf("Leaf XA")); comp.add(new Leaf("Leaf XB")); root.add(comp); // 分枝 Composite X上再長出分枝 Composite XY ,分枝上也有兩葉Leaf XYA 和Leaf XYB Composite comp2 = new Composite("Composite XY"); comp2.add(new Leaf("Leaf XYA")); comp2.add(new Leaf("Leaf XYB")); comp.add(comp2); // 根部又長出兩葉LeafC 和LeafD,惋惜LeafD沒長牢,被風吹走了 root.add(new Leaf("Leaf C")); Leaf leafD = new Leaf("Leaf D"); root.add(leafD); root.remove(leafD); // 顯示大樹 root.dispaly(1); } }
- root ---- Leaf A ---- Leaf B ---- Composite X ------- Leaf XA ------- Leaf XB ------- Composite XY ---------- Leaf XYA ---------- Leaf XYB ---- Leaf C
樹可能有無數的分枝,反覆使用 Composite 就能夠實現樹狀結構,但樹葉不能夠再長分枝,爲何此處 Leaf 當中也有實現 add 和 remove?app
這種叫作透明方式,也就是說在 Component 中聲明全部用來管理子對象的方法,其中包括 add, remove 等。這樣實現 Component 接口的全部子類都具有了 add 和 remove。這樣作的好處是葉節點和枝節點對於外界沒有區別,它們具有徹底一致的行爲接口,但問題也明顯,由於自己不具體 add 和 remove 功能,因此實現是沒有意義的。ide
固然也能夠不去實現,這種叫作安全方式,也就是在 Component 接口中不去聲明 add 和 remove 方法,那麼子類的 Leaf 也就不須要去實現,而是在 Composite 聲明全部用來管理子類對象的方法,不過因爲不夠透明,因此樹葉和樹枝將不具備相同的接口,客戶端的調用須要作相應的判斷,帶來了不便。測試
當需求中是體現部分與總體層次的結構時,以及但願用戶能夠忽略組合對象與單個對象的不一樣,統一的使用組合結構中的全部對象時,就應該考慮用組合模式了。ui
總公司與分公司關係,總公司的全部管理功能一樣能使用在分公司。this
/** * 公司抽象類 * Created by callmeDevil on 2019/8/11. */ public abstract class Company { protected String name; public Company(String name){ this.name = name; } public abstract void add(Company c); public abstract void remove(Company c); public abstract void dispaly(int depth); public abstract void lineOfDuty(); // 履行職責,不一樣部門須要履行不一樣的職責 // 用於輸出層次結構,非必須,與模式無關 public String getDepth(int depth){ StringBuilder sb = new StringBuilder(depth); for (int i = 0; i < depth; i++) { sb.append("-"); } return sb.toString(); } }
/** * 具體公司(樹枝節點) * Created by callmeDevil on 2019/8/11. */ public class ConcreteCompany extends Company { private List<Company> children = new ArrayList<>(); public ConcreteCompany(String name) { super(name); } @Override public void add(Company c) { children.add(c); } @Override public void remove(Company c) { children.remove(c); } @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); for (Company child : children) { child.dispaly(depth + 3); } } @Override public void lineOfDuty() { for (Company child : children) { child.lineOfDuty(); } } }
/** * 人力資源部(樹葉節點) * Created by callmeDevil on 2019/8/11. */ public class HRDepartment extends Company{ public HRDepartment(String name){ super(name); } @Override public void add(Company c) {} @Override public void remove(Company c) {} @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); } @Override public void lineOfDuty() { System.out.println(String.format("%s 員工招聘培訓管理", name)); } }
/** * 財務部(樹葉節點) * Created by callmeDevil on 2019/8/11. */ public class FinanceDepartment extends Company{ public FinanceDepartment(String name){ super(name); } @Override public void add(Company c) {} @Override public void remove(Company c) {} @Override public void dispaly(int depth) { System.out.println(String.format("%s %s", getDepth(depth), name)); } @Override public void lineOfDuty() { System.out.println(String.format("%s 公司財務收支管理", name)); } }
public class Test { public static void main(String[] args) { ConcreteCompany root = new ConcreteCompany("北京總公司"); root.add(new HRDepartment("總公司人力資源部")); root.add(new FinanceDepartment("總公司財務部")); ConcreteCompany comp = new ConcreteCompany("上海分公司"); comp.add(new HRDepartment("上海分公司人力資源部")); comp.add(new FinanceDepartment("上海分公司財務部")); root.add(comp); ConcreteCompany comp1 = new ConcreteCompany("南京辦事處"); comp1.add(new HRDepartment("南京辦事處人力資源部")); comp1.add(new FinanceDepartment("南京辦事處財務部")); comp.add(comp1); ConcreteCompany comp2 = new ConcreteCompany("杭州辦事處"); comp2.add(new HRDepartment("杭州辦事處人力資源部")); comp2.add(new FinanceDepartment("杭州辦事處財務部")); comp.add(comp2); System.out.println("\n 結構圖:"); root.dispaly(1); System.out.println("\n 職責:"); root.lineOfDuty(); } }
結構圖: - 北京總公司 ---- 總公司人力資源部 ---- 總公司財務部 ---- 上海分公司 ------- 上海分公司人力資源部 ------- 上海分公司財務部 ------- 南京辦事處 ---------- 南京辦事處人力資源部 ---------- 南京辦事處財務部 ------- 杭州辦事處 ---------- 杭州辦事處人力資源部 ---------- 杭州辦事處財務部 職責: 總公司人力資源部 員工招聘培訓管理 總公司財務部 公司財務收支管理 上海分公司人力資源部 員工招聘培訓管理 上海分公司財務部 公司財務收支管理 南京辦事處人力資源部 員工招聘培訓管理 南京辦事處財務部 公司財務收支管理 杭州辦事處人力資源部 員工招聘培訓管理 杭州辦事處財務部 公司財務收支管理