組合模式的定義:又叫作整體-部分(Part-Whole)模式,通過將單個物件(葉節點)和組合物件用相同的介面表示,使客戶端對單個物件和組合物件的訪問具有一致性,它是一種將物件組合成樹狀的層次結構的模式,屬于結構型設計模式,
組合模式一般用來描述整體與部分的關系,它將物件組合到樹狀結構,頂層的節點被稱為根節點,最末級的節點成為葉節點,中間的節點成為樹枝節點,樹形結構如下圖,

由上圖可以看出,根節點和樹枝節點本質上屬于同一種資料型別,可以作為容器使用;而葉節點與樹枝節點在語意上不屬于同一種型別,但是在組合模式中,我們會把樹枝節點和葉節點看作同一種資料型別(用統一介面定義),讓它們具備一致行為,這樣,在組合模式中,整個樹形結構中的物件都屬于同一種型別,客戶端不需要辨別是樹枝節點還是葉子節點,可以直接進行操作,給客戶端的使用帶來極大的便利,
組合模式的結構:組合模式包含以下3個角色,
- 抽象根節點(Component):為葉節點和樹枝節點宣告公共介面,并實作它們的默認行為,
- 樹葉節點(Leaf):組合中的葉節點物件,它沒有子節點,是樹狀結構的最末級,
- 樹枝節點(Composite):組合中的分支節點物件,它有子節點,主要作用是存盤和管理子節點,
組合模式的實作:組合模式分為透明式組合模式和安全式組合模式,我們以公司組織架構為例,分別用透明式組合模式和安全式組合模式實作,
某公司組織架構如下圖,公司包括銷售部、研發部和財務部,銷售部和財務部下又分為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;
}
@Override
public void add(DeptComponent deptComponent) { }
@Override
public void remove(DeptComponent deptComponent) { }
@Override
public List<DeptComponent> getChildren() {
return null;
}
@Override
public 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;
}
@Override
public void add(DeptComponent deptComponent) {
children.add(deptComponent);
}
@Override
public void remove(DeptComponent deptComponent) {
children.remove(deptComponent);
}
@Override
public List<DeptComponent> getChildren() {
return children;
}
@Override
public 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;
}
@Override
public 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;
}
@Override
public 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());
}
});
}
}
安全組合模式的結構圖:

組合模式的優點:
- 組合模式使客戶端處理單個物件和組合物件邏輯一致,這簡化了客戶端代碼;
- 更容易在組合體內加入新的物件,滿足“開閉原則”;
組合模式的缺點:
- 設計較復雜,客戶端需要花更多時間理清類之間的層次關系;
- 不容易限制容器中的構件;
- 不容易用繼承的方法來增加構件的新功能;
組合模式的使用場景:
- 在需要表示一個物件整體與部分的層次結構的場合,
- 要求對客戶端隱藏組合物件與單個物件的差異,使客戶端可以用統一的介面使用組合結構中的所有物件的場合,
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271306.html
標籤:其他
上一篇:分布式系統(4)分布式事務
下一篇:MHA資料庫高可用架構
