深度解析設計模式之組合模式
一、介紹
組合模式(Composite Pattern),又叫部分整體模式,依據(jù)樹形結構來組合對象,用來表示部分以及整體層次。
組合模式 一般用來描述整體與部分的關系,它將對象組織到樹形結構中,最頂層的節(jié)點稱為根節(jié)點,根節(jié)點下面可以包含樹枝節(jié)點和葉子節(jié)點,樹枝節(jié)點下面又可以包含樹枝節(jié)點和葉子節(jié)點。如下圖所示:
在組合模式中,會把樹枝節(jié)點和葉子節(jié)點認為是同一種數(shù)據(jù)類型(用同一接口定義),讓它們具備一致行為。
這樣,整個樹形結構中的對象都是同一種類型,帶來的一個好處就是客戶無需辨別 樹枝節(jié)點還是葉子節(jié)點,而是可以直接進行操作,給客戶使用帶來極大的便利。
從設計的角度看,組合模式涉及到三個角色:
抽象根節(jié)點:它是一個抽象接口,定義了算法;
具體節(jié)點:實現(xiàn)或繼承自抽象根節(jié)點,完成具體算法操作;
客戶端:客戶類提出使用具體類的請求;
二、示例
下面,我們拿學校的組織架構為例,比如說一個學校,包含了后勤部、網絡部、教學部、保衛(wèi)部、分校等部門組成,每一個分校,同樣具有后勤部、網絡部這些。既然這些部門都是學校的部門,基本的操作應該都是一樣的,我們可以將所有的部門都拉入學校屬性。
用類圖表示如下:
實現(xiàn)過程如下!
- /**
- * 學校接口
- */
- public interface School {
- /**
- * 添加分?;蛘卟块T
- * @param school
- */
- void addPart(School school);
- /**
- * 移除分?;蛘卟块T
- * @param school
- */
- void removePart(School school);
- /**
- * 展示分?;蛘卟块T信息
- */
- void displayPart();
- }
然后,創(chuàng)建一個學校具體實現(xiàn)類ConcreteSchool,可以是總校,也可以是分校,如下:
- /**
- * 具體學校,可以是總校,也可以是分校
- */
- public class ConcreteSchool implements School {
- private String name;//名稱
- private List<School> partList = new ArrayList<>();
- public ConcreteSchool(String name) {
- this.name = name;
- }
- @Override
- public void addPart(School school) {
- partList.add(school);
- }
- @Override
- public void removePart(School school) {
- partList.remove(school);
- }
- /**
- * 學校查看部門信息
- */
- @Override
- public void displayPart() {
- for (School school : partList) {
- school.displayPart();
- }
- }
- }
接著,創(chuàng)建兩個具體的部門,網絡部門InternetDepartment、安全部門SecurityDepartment,代碼如下:
- /**
- * 網絡部門
- */
- public class InternetDepartment implements School {
- private String name;//名稱
- public InternetDepartment(String name) {
- this.name = name;
- }
- @Override
- public void addPart(School school) {}
- @Override
- public void removePart(School school) {}
- @Override
- public void displayPart() {
- System.out.println("我是" + name + ",負責學校的網絡管理");
- }
- }
- /**
- * 安全部門
- */
- public class SecurityDepartment implements School {
- private String name;//名稱
- public SecurityDepartment(String name) {
- this.name = name;
- }
- @Override
- public void addPart(School school) {}
- @Override
- public void removePart(School school) {}
- @Override
- public void displayPart() {
- System.out.println("我是" + name + ",負責學校的安全工作");
- }
- }
最后,編寫一個測試類,如下:
- public class CompositeClient {
- public static void main(String[] args) {
- //總校部門
- ConcreteSchool rootSchool = new ConcreteSchool("總校");
- rootSchool.addPart(new InternetDepartment("總校網絡部門"));
- rootSchool.addPart(new SecurityDepartment("總校安全部門"));
- //分校部門
- ConcreteSchool branchSchool = new ConcreteSchool("分校");
- branchSchool.addPart(new InternetDepartment("分校網絡部門"));
- branchSchool.addPart(new SecurityDepartment("分校安全部門"));
- rootSchool.addPart(branchSchool);
- rootSchool.displayPart();//展示信息
- }
- }
輸出結果:
- 我是總校網絡部門,負責學校的網絡管理
- 我是總校安全部門,負責學校的安全工作
- 我是分校網絡部門,負責學校的網絡管理
- 我是分校安全部門,負責學校的安全工作
從上面的例子,可以很清晰看到類的層次關系,所有的具體對象當作一個單一的對象School來處理。
三、應用
在 Java 的 GUI 容器組件中,就用到了組合模式,所有的子類組件,都可以看作為容器對象。
當然,還有我們使用的 Mybatis 在處理動態(tài) SQL 節(jié)點時,也應用到了組合設計模式,Mybatis 會將映射配置文件中定義的動態(tài) SQL 節(jié)點、文本節(jié)點等解析成對應的 SqlNode 實現(xiàn),并形成樹形結構。
四、總結
當想表達對象的部分-整體的層次結構時,推薦采用組合模式進行設計。
五、參考
1、java的架構師技術棧 - 23種設計模式之組合模式
2、菜鳥教程 -組合模式