簡介 組合模式(Composite Pattern),又叫部分整體模式,是一種結構型設計模式。用於把一組類似的對象當作一個單一的對象來看。組合模式依據樹形結構來組合對象,用不同組件來構建某個部分或整體對象。 如果你需要實現樹狀對象結構,可以使用組合模式。如果你希望客戶端代碼以相同方式處理簡單和複雜元 ...
簡介
組合模式(Composite Pattern),又叫部分整體模式,是一種結構型設計模式。用於把一組類似的對象當作一個單一的對象來看。組合模式依據樹形結構來組合對象,用不同組件來構建某個部分或整體對象。
如果你需要實現樹狀對象結構,可以使用組合模式。如果你希望客戶端代碼以相同方式處理簡單和複雜元素,可以使用該模式。
作用
- 符合開閉原則。無需更改現有代碼,就可以在應用中添加新元素,使之成為對象樹的一部分。
- 模糊了簡單元素和複雜元素的概念,程式可以像處理簡單元素一樣來處理複雜元素,從而使得程式與複雜元素的內部結構解耦。
實現步驟
- 創建抽象構件(Component)介面,用於聲明樹葉構件和樹枝構件的預設行為。
- 創建樹枝構件(Composite)角色 / 中間構件:是組合中的分支節點對象,它有子節點,用於繼承和實現抽象構件。它的主要作用是存儲和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。
- 定義樹葉構件(Leaf)角色:是組合中的葉子節點對象,它沒有子節點,用於繼承或實現抽象構件。
UML
Java語言代碼
基礎部件介面
// OrganizationComponent.java 定義部件介面或抽象類,分支和葉子節點遵循該類約定 public interface OrganizationComponent { public void add(OrganizationComponent component); public void remove(OrganizationComponent component); public OrganizationComponent getChild(int index); public void operation(); public String getName(); }
具體部件實現
// CompanyComposite.java 實現部件的樹枝構件1 public class CompanyComposite implements OrganizationComponent { private String name; private List<OrganizationComponent> children = new ArrayList<OrganizationComponent>(); public CompanyComposite(String name) { this.name = name; } public void add(OrganizationComponent component) { children.add(component); } public void remove(OrganizationComponent component) { children.remove(component); } public OrganizationComponent getChild(int index) { return children.get(index); } public void operation() { System.out.println(this.getClass().getName() + " CompanyComposite::operation() " + this.name); for (Object component : children) { ((OrganizationComponent) component).operation(); } } public String getName() { return name; } }
// DepartmentComposite.java 實現部件的樹枝構件2 public class DepartmentComposite implements OrganizationComponent { private String name; private List<OrganizationComponent> children = new ArrayList<OrganizationComponent>(); public DepartmentComposite(String name) { this.name = name; } public void add(OrganizationComponent component) { children.add(component); } public void remove(OrganizationComponent component) { children.remove(component); } public OrganizationComponent getChild(int index) { return children.get(index); } public void operation() { System.out.println(this.getClass().getName() + " DepartmentComposite::operation() " + this.name); for (Object component : children) { ((OrganizationComponent) component).operation(); } } public String getName() { return name; } }
// EmployeeLeaf.java 實現部件的葉子節點,葉子節點不能再含有子節點 public class EmployeeLeaf implements OrganizationComponent { private String name; public EmployeeLeaf(String name) { this.name = name; } // 葉子節點不能再增加內容 public void add(OrganizationComponent component) { System.out.println("Leaf can't add."); } // 葉子節點沒有移除內容 public void remove(OrganizationComponent component) { System.out.println("Leaf can't remove."); } // 葉子節點無獲取子節點 public OrganizationComponent getChild(int index) { System.out.println("Leaf can't getChild."); return null; } public void operation() { System.out.println(this.getClass().getName() + " EmployeeLeaf::operation() " + this.name); } public String getName() { return name; } }
測試調用
/** * 組合模式依據樹形結構來組合對象,用不同組件來構建整體對象。 * 不同組件之間有相同的介面約束,有不同的具體實現。 * 先定義頂級節點,然後陸續加入枝葉節點和葉子節點,這樣不斷添加,將零散的個體組成一個整體。 */ // 通過組合模型組合了一個部件,分支和節點可以隨意增刪 OrganizationComponent com = new CompanyComposite("西天旅游有限公司"); OrganizationComponent com1 = new DepartmentComposite("總裁辦"); OrganizationComponent com2 = new DepartmentComposite("行動隊"); OrganizationComponent com3 = new DepartmentComposite("後勤組"); OrganizationComponent leaf1 = new EmployeeLeaf("唐三藏"); OrganizationComponent leaf2 = new EmployeeLeaf("孫悟空"); OrganizationComponent leaf3 = new EmployeeLeaf("豬悟能"); OrganizationComponent leaf4 = new EmployeeLeaf("沙悟凈"); com.add(com1); com.add(com2); com.add(com3); // leaf1屬於com1 com1.add(leaf1); // leaf2, leaf3屬於com2 com2.add(leaf2); com2.add(leaf3); // 添加再刪除 DepartmentComposite dept1 = new DepartmentComposite("小分隊"); com2.add(dept1); EmployeeLeaf tmp1 = new EmployeeLeaf("臨時工"); dept1.add(tmp1); dept1.remove(tmp1); // leaf4屬於com3 com3.add(leaf4); // 執行全部節點動作 com.operation(); // 獲取某個節點 OrganizationComponent employee = (EmployeeLeaf) com.getChild(1).getChild(0); System.out.println(employee.getName());
C語言代碼
func.h 自定義頭文件 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> // 定義部件介面或抽象類,分支和葉子節點遵循該類約定 typedef struct OrganizationComponent { char name[200]; void (*add)(struct OrganizationComponent *, struct OrganizationComponent *); void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *); struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int); void (*operation)(struct OrganizationComponent *); int children_size; struct OrganizationComponent **children; // 如果是柔型數組,則自動擴展數組長度,但可能導致出現亂碼現象,故採取固定長度數組 // struct OrganizationComponent *children[]; } OrganizationComponent; void add_component(OrganizationComponent *, OrganizationComponent *); void remove_component(OrganizationComponent *, OrganizationComponent *); OrganizationComponent *get_child_component(OrganizationComponent *, int); void print_children(OrganizationComponent *children[], int children_size); // 實現部件的樹枝構件1 typedef struct CompanyComposite { char name[200]; void (*add)(struct OrganizationComponent *, struct OrganizationComponent *); void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *); struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int); void (*operation)(struct CompanyComposite *); int children_size; struct OrganizationComponent **children; } CompanyComposite; CompanyComposite *company_composite_constructor(char *name); // 實現部件的樹枝構件2 typedef struct DepartmentComposite { char name[200]; void (*add)(struct OrganizationComponent *, struct OrganizationComponent *); void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *); struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int); void (*operation)(struct DepartmentComposite *); int children_size; struct OrganizationComponent **children; } DepartmentComposite; DepartmentComposite *department_composite_constructor(char *name); // 實現部件的葉子節點,葉子節點不能再含有子節點 typedef struct EmployeeLeaf { char name[200]; void (*add)(struct OrganizationComponent *, struct OrganizationComponent *); void (*remove)(struct OrganizationComponent *, struct OrganizationComponent *); struct OrganizationComponent *(*get_child)(struct OrganizationComponent *, int); void (*operation)(struct EmployeeLeaf *); int children_size; struct OrganizationComponent **children; } EmployeeLeaf; EmployeeLeaf *employee_leaf_constructor(char *name);
基礎部件介面
// organization_component.c 定義部件介面或抽象類,分支和葉子節點遵循該類約定 #include "func.h" // 定義部件介面或抽象類,分支和葉子節點遵循該類約定 // C語言沒有介面和抽象類,用struct替代,同時把公共函數聲明在這裡 // 添加一個組件到子節點中 void add_component(OrganizationComponent *parent, OrganizationComponent *component) { // 先將原數組保留下來 OrganizationComponent **old_children = parent->children; parent->children_size += 1; // 新申請空間給子節點數組 parent->children = (OrganizationComponent **)calloc(parent->children_size, sizeof(OrganizationComponent *)); for (int i = 0; i < parent->children_size - 1; i++) { parent->children[i] = old_children[i]; } // 將組件追加到子節點數組中 parent->children[parent->children_size - 1] = component; free(old_children); } // 移除第一個匹配的子節點 void remove_component(OrganizationComponent *parent, OrganizationComponent *component) { int size = parent->children_size; // 初始化組件id大於數組長度 int com_idx = size; for (int i = 0; i < size; i++) { // 找到第一個匹配的組件下標 if (parent->children[i] == component) { com_idx = i; } // 自匹配項開始,後項逐個往前移動1位 if (i >= com_idx) { parent->children[i] = parent->children[i + 1]; // 最後一項置空且總長度減少1位 if (i == size - 1) { parent->children[i] = NULL; parent->children_size -= 1; } } } } // 列印全部子節點 void print_children(OrganizationComponent *children[], int children_size) { for (int i = 0; i < children_size; i++) { printf("\r\n children[%d]=%s", i, children[i]->name); } } // 根據下標獲取子節點 OrganizationComponent *get_child_component(OrganizationComponent *component, int index) { return component->children[index]; }
具體部件實現
// company_composite.c 實現部件的樹枝構件1 #include "func.h" // 實現部件的樹枝構件1 void company_composite_operation(CompanyComposite *component) { printf("\r\n CompanyComposite::operation() [name=%s]", component->name); print_children(component->children, component->children_size); for (int i = 0; i < component->children_size; i++) { if (component->children[i] != NULL) { component->children[i]->operation(component->children[i]); } } } // 創建CompanyComposite對象 CompanyComposite *company_composite_constructor(char *name) { OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent)); strncpy(component->name, name, 200); component->add = &add_component; component->remove = &remove_component; component->children_size = 0; component->get_child = &get_child_component; // 轉為CompanyComposite CompanyComposite *company_composite = (CompanyComposite *)component; company_composite->operation = &company_composite_operation; return company_composite; }
// department_composite.c 實現部件的樹枝構件2 #include "func.h" // 實現部件的樹枝構件2 void department_composite_operation(DepartmentComposite *component) { printf("\r\n DepartmentComposite::operation() [name=%s]", component->name); print_children(component->children, component->children_size); for (int i = 0; i < component->children_size; i++) { if (component->children[i] != NULL) { component->children[i]->operation(component->children[i]); } } } // 創建DepartmentComposite對象 DepartmentComposite *department_composite_constructor(char *name) { OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent)); strncpy(component->name, name, 200); component->add = &add_component; component->remove = &remove_component; component->children_size = 0; component->get_child = &get_child_component; // 轉為DepartmentComposite DepartmentComposite *department_composite = (DepartmentComposite *)component; department_composite->operation = &department_composite_operation; return department_composite; }
// employee_leaf.c 實現部件的葉子節點,葉子節點不能再含有子節點 #include "func.h" // 實現部件的葉子節點,葉子節點不能再含有子節點 // 葉子節點不能再增加內容 void add_leaf_component(OrganizationComponent *parent, OrganizationComponent *component) { printf("\r\n Leaf can't add."); } // 葉子節點沒有移除內容 void remove_leaf_component(OrganizationComponent *parent, OrganizationComponent *component) { printf("\r\n Leaf can't remove."); } // 葉子節點不能獲取子節點 OrganizationComponent *get_leaf_child_component(OrganizationComponent *component, int index) { printf("\r\n Leaf can't get_child."); return NULL; } // 子節點的操作函數 void employee_leaf_operation(EmployeeLeaf *component) { printf("\r\n EmployeeLeaf::operation() [name=%s]", component->name); } // 創建EmployeeLeaf對象 EmployeeLeaf *employee_leaf_constructor(char *name) { OrganizationComponent *component = (OrganizationComponent *)malloc(sizeof(OrganizationComponent)); strncpy(component->name, name, 200); component->children_size = 0; component->add = &add_leaf_component; component->remove = &remove_leaf_component; component->get_child = &get_leaf_child_component; // 轉為EmployeeLeaf EmployeeLeaf *employee_leaf = (EmployeeLeaf *)component; employee_leaf->operation = &employee_leaf_operation; return employee_leaf; }
測試調用
/** * 組合模式依據樹形結構來組合對象,用不同組件來構建整體對象。 * 不同組件之間有相同的介面約束,有不同的具體實現。 * 先定義頂級節點,然後陸續加入枝葉節點和葉子節點,這樣不斷添加,將零散的個體組成一個整體。ss */ // 通過組合模型組合了一個部件,分支和節點可以隨意增刪 OrganizationComponent *com = (OrganizationComponent *)company_composite_constructor("西天旅游有限公司"); OrganizationComponent *com1 = (OrganizationComponent *)department_composite_constructor("總裁辦"); OrganizationComponent *com2 = (OrganizationComponent *)department_composite_constructor("行動隊"); OrganizationComponent *com3 = (OrganizationComponent *)department_composite_constructor("後勤組"); OrganizationComponent *leaf1 = (OrganizationComponent *)employee_leaf_constructor("唐三藏"); OrganizationComponent *leaf2 = (OrganizationComponent *)employee_leaf_constructor("孫悟空"); OrganizationComponent *leaf3 = (OrganizationComponent *)employee_leaf_constructor("豬悟能"); OrganizationComponent *leaf4 = (OrganizationComponent *)employee_leaf_constructor("沙悟凈"); com->add(com, com1); com->add(com, com2); com->add(com, com3); // leaf1屬於com1 com1->add(com1, leaf1); // leaf2, leaf3屬於com2 com2->add(com2, leaf2); com2->add(com2, leaf3); // 添加再刪除 DepartmentComposite *dept1 = department_composite_constructor("小分隊"); com2->add(com2, (OrganizationComponent *)dept1); EmployeeLeaf *tmp1 = employee_leaf_constructor("臨時工"); dept1->add((OrganizationComponent *)dept1, (OrganizationComponent *)tmp1); dept1->remove((OrganizationComponent *)dept1, (OrganizationComponent *)tmp1); // leaf4屬於com3 com3->add(com3, leaf4); // 執行全部節點動作 com->operation(com); // 獲取某個節點 OrganizationComponent *dept2 = com->get_child(com, 1); EmployeeLeaf *employee_child1 = (EmployeeLeaf *)dept2->get_child(dept2, 0); printf("\r\n [employee->name=%s]", employee_child1->name);
更多語言版本
不同語言實現設計模式源碼,請查看:https://github.com/microwind/design-pattern