设计模式系列:搞懂组合模式,单对象与组合对象对外统一接口
組合模式的定義:又叫作整體-部分(Part-Whole)模式,通過將單個對象(葉節點)和組合對象用相同的接口表示,使客戶端對單個對象和組合對象的訪問具有一致性。它是一種將對象組合成樹狀的層次結構的模式。屬于結構型設計模式。
組合模式一般用來描述整體與部分的關系,它將對象組合到樹狀結構,頂層的節點被稱為根節點,最末級的節點成為葉節點,中間的節點成為樹枝節點,樹形結構如下圖。
? ? ? ? 由上圖可以看出,根節點和樹枝節點本質上屬于同一種數據類型,可以作為容器使用;而葉節點與樹枝節點在語義上不屬于同一種類型,但是在組合模式中,我們會把樹枝節點和葉節點看作同一種數據類型(用統一接口定義),讓它們具備一致行為。這樣,在組合模式中,整個樹形結構中的對象都屬于同一種類型,客戶端不需要辨別是樹枝節點還是葉子節點,可以直接進行操作,給客戶端的使用帶來極大的便利。
組合模式的結構:組合模式包含以下3個角色。
組合模式的實現:組合模式分為透明式組合模式和安全式組合模式。我們以公司組織架構為例,分別用透明式組合模式和安全式組合模式實現。
某公司組織架構如下圖,公司包括銷售部、研發部和財務部,銷售部和財務部下又分為A組和B組。
透明組合模式的實現:
? ? ? ? 在透明組合模式中,抽象根節點聲明了所有子類中的全部方法,客戶端無須區別葉節點和樹枝節點,它們具備一致的接口,對客戶端來說是透明的。但其缺點是:葉節點本來沒有增加 Add()、刪除Remove() 及 獲取子節點GetChild() 的方法,卻要實現它們(空實現或拋出異常),這樣會帶來一些安全性問題。
//抽象根節點 public interface DeptComponent {void add(DeptComponent deptComponent);void remove(DeptComponent deptComponent);List<DeptComponent> getChildren();void getName(); }//葉節點 public class LeafDept implements DeptComponent {private String name;public LeafDept(String name){this.name = name;}@Overridepublic void add(DeptComponent deptComponent) { }@Overridepublic void remove(DeptComponent deptComponent) { }@Overridepublic List<DeptComponent> getChildren() {return null;}@Overridepublic void getName() {System.out.println(name+"前來報到!");} }//樹枝節點 public class CompositeDept implements DeptComponent{private List<DeptComponent> children = new ArrayList<>();private String name;CompositeDept(String name){this.name = name;}@Overridepublic void add(DeptComponent deptComponent) {children.add(deptComponent);}@Overridepublic void remove(DeptComponent deptComponent) {children.remove(deptComponent);}@Overridepublic List<DeptComponent> getChildren() {return children;}@Overridepublic void getName() {System.out.println(name+"前來報到!");} }//測試類 public class CompositeTest {public static void main(String[] args) {DeptComponent company = new CompositeDept("某公司");DeptComponent saleDept = new CompositeDept("銷售部");DeptComponent developmentDept = new CompositeDept("研發部");DeptComponent financeDept = new CompositeDept("財務部");DeptComponent saleA = new LeafDept("銷售部A組");DeptComponent saleB = new LeafDept("銷售部B組");DeptComponent developmentA = new LeafDept("研發部A組");DeptComponent developmentB = new LeafDept("研發部B組");developmentDept.add(developmentA);developmentDept.add(developmentB);saleDept.add(saleA);saleDept.add(saleB);company.add(saleDept);company.add(developmentDept);company.add(financeDept);List<DeptComponent> children = company.getChildren();children.stream().forEach(deptComponent -> {deptComponent.getName();deptComponent.getChildren().stream().forEach(deptComponent1 -> deptComponent1.getName());});} }透明組合模式的結構圖:
安全組合模式的實現:
? ? ? ? 在安全組合模式中,將管理葉節點的方法移到樹枝節點中,抽象根節點和葉節點沒有對子對象的管理方法,避免了透明組合模式的安全性問題,但由于葉節點和樹枝節點有不同的接口,客戶端在調用時要知道葉節點和樹枝節點的存在,所以失去了透明性。
//抽象根節點 public interface DeptComponent {void getName(); }//葉節點 public class LeafDept implements DeptComponent {private String name;public LeafDept(String name){this.name = name;}@Overridepublic void getName() {System.out.println(name+"前來報到!");} }//樹枝節點 public class CompositeDept implements DeptComponent{private List<DeptComponent> children = new ArrayList<>();private String name;CompositeDept(String name){this.name = name;}public void add(DeptComponent deptComponent) {children.add(deptComponent);}public void remove(DeptComponent deptComponent) {children.remove(deptComponent);}public List<DeptComponent> getChildren() {return children;}@Overridepublic void getName() {System.out.println(name+"前來報到!");} }//測試類 public class CompositeTest {public static void main(String[] args) {CompositeDept company = new CompositeDept("某公司");CompositeDept saleDept = new CompositeDept("銷售部");CompositeDept developmentDept = new CompositeDept("研發部");CompositeDept financeDept = new CompositeDept("財務部");DeptComponent saleA = new LeafDept("銷售部A組");DeptComponent saleB = new LeafDept("銷售部B組");DeptComponent developmentA = new LeafDept("研發部A組");DeptComponent developmentB = new LeafDept("研發部B組");developmentDept.add(developmentA);developmentDept.add(developmentB);saleDept.add(saleA);saleDept.add(saleB);company.add(saleDept);company.add(developmentDept);company.add(financeDept);List<DeptComponent> children = company.getChildren();children.stream().forEach(deptComponent -> {deptComponent.getName();if(deptComponent instanceof CompositeDept){CompositeDept compositeDept = (CompositeDept) deptComponent;compositeDept.getChildren().stream().forEach(deptComponent1 -> deptComponent1.getName());}});} }安全組合模式的結構圖:
組合模式的優點:
組合模式的缺點:
組合模式的使用場景:
總結
以上是生活随笔為你收集整理的设计模式系列:搞懂组合模式,单对象与组合对象对外统一接口的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: modbus通讯失败_STM32 MOD
- 下一篇: asp.net ajax控件工具集 Au