天天看點

結構型模式:組合模式(Composite Pattern)

一、設計模式的分類

(如果以前看過關于設計模式的分類的話,這部分可以忽略!)

經過很多大神的總結,目前Java中一共23種經典的設計模式!

按照目的,設計模式可以分為以下三種用途:

1.建立型模式:用來處理對象的建立過程

2.結構型模式:用來處理類或者對象的組合

3.行為型模式:用來對類或對象怎樣互動和怎樣配置設定職責進行描述

建立型模式用來處理對象的建立過程,主要包含以下5種設計模式:

 工廠方法模式(Factory Method Pattern)

 抽象工廠模式(Abstract Factory Pattern)

 建造者模式(Builder Pattern)

 原型模式(Prototype Pattern)

 單例模式(Singleton Pattern)

結構型模式用來處理類或者對象的組合,主要包含以下7種設計模式:

 擴充卡模式(Adapter Pattern)

 橋接模式(Bridge Pattern)

 組合模式(Composite Pattern)

 裝飾者模式(Decorator Pattern)

 外觀模式(Facade Pattern)

 享元模式(Flyweight Pattern)

 代理模式(Proxy Pattern)

行為型模式用來對類或對象怎樣互動和怎樣配置設定職責進行描述,主要包含以下11種設計模式:

 責任鍊模式(Chain of Responsibility Pattern)

 指令模式(Command Pattern

 解釋器模式(Interpreter Pattern)

 疊代器模式(Iterator Pattern)

 中介者模式(Mediator Pattern)

 備忘錄模式(Memento Pattern)

 觀察者模式(Observer Pattern)

 狀态模式(State Pattern)

 政策模式(Strategy Pattern)

 模闆方法模式(Template Method Pattern)

 通路者模式(Visitor Pattern) 

本篇文章主要為講解一下組合模式(Composite Pattern)!

注:概念性的東西可以忽略不看,可以在看完例子以後再看概念,這樣更有利于了解!

二、組合模式概述

(注:建議沒有看過組合模式的朋友們,先看執行個體,然後再看枯燥的概念)

看到Composite組合模式的時候你就應該往樹形結構圖上去想,這樣更有利于你去了解組合模式!

組合模式定義:将對象以樹形結構組織起來,以達成"部分--整體"的層次結構,使得用戶端對單個對象群組合對象的使用具有一緻性,友善用戶端的使用。

組合體内所有的對象都有共同的接口,當組合體中某一個對象的方法被調用執行時,組合模式Composite将周遊整個樹形結構,尋找同樣包含這個方法的對象并實作調用執行(可以在執行個體中感受一下,隻看概念你會感覺知識點很空洞)。

組合模式讓你可以優化處理遞歸或分級資料結構。有許多關于分級資料結構的例子,使得組合模式非常有用武之地。關于分級資料結構的一個普遍性的例子是你每次使用電腦時所遇到的:檔案系統。檔案系統由目錄和檔案組成,每個目錄都可以裝内容。目錄的内容可以是檔案,也可以是目錄。按照這種方式,計算機的檔案系統就是以遞歸結構來組織的。如果你想要描述這樣的資料結構,那麼你可以使用組合模式Composite。

組合模式涉及角色:

1、Component是組合模式中的對象聲明接口,在适當的情況下,它實作所有類共有接口的預設行為。聲明一個接口用于通路和管理Component子部件。

  2、Leaf 在組合模式中表示葉子結點對象(沒有子節點)。

  3、Composite用來定義有枝節點行為,存儲子部件,在Component接口中實作與子部件有關操作,如增加(add)和删除(remove)等。

三、類圖

結構型模式:組合模式(Composite Pattern)
結構型模式:組合模式(Composite Pattern)

四、執行個體說明

如果你想要建立層次結構,并可以在其中以相同的方式對待所有元素,那麼組合模式就是最理想的選擇。

下面使用一個檔案系統的例子來舉例說明組合模式的用途。在例子中,檔案和目錄都繼承相同的接口,這是組合模式的關鍵。通過繼承相同的接口,你就可以用相同的方式對待檔案和目錄,進而實作将檔案或者目錄儲存為目錄的子級元素。

舉例如下:

注:雖然下面的例子并沒有真正的生成檔案目錄結構,我們就假設生成的是目錄結構,而下面的name屬性就當做是檔案或者目錄的名字!

  1. public abstract class Company {  
  2.     private String name;  
  3.     public Company(String name) {  
  4.         this.name = name;  
  5.     }  
  6.     public Company() {  
  7.     }  
  8.     public String getName() {  
  9.         return name;  
  10.     }  
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.     protected abstract void add(Company company);   //添加
  15.     protected abstract void romove(Company company);//删除  
  16.     protected abstract void display(int depth);     //顯示
  17. }  
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3. public class ConcreteCompany extends Company {  
  4.     private List<Company> cList;  
  5.     public ConcreteCompany() {  
  6.         cList = new ArrayList<Company>();  
  7.     }  
  8.     public ConcreteCompany(String name) {  
  9.         super(name);   
  10.         cList = new ArrayList<Company>() ;   
  11.     }  
  12.     @Override  
  13.     protected void add(Company company) {  
  14.         cList.add(company);  
  15.     }  
  16.     @Override  
  17.     protected void display(int depth) {//深度
  18.         StringBuilder sb = new StringBuilder("");  
  19.         for (int i = 0; i < depth; i++) {  
  20.             sb.append("-");   
  21.         }
  22.         System.out.println(new String(sb) + this.getName());  
  23.         for (Company c : cList) {  
  24.             c.display(depth + 2);  
  25.         }  
  26.     }  
  27.     @Override  
  28.     protected void romove(Company company) {  
  29.         cList.remove(company);  
  30.     }  
  31. }    
  1. public class FinanceDepartment extends Company {//葉子節點
  2.     public FinanceDepartment(){  
  3.     }  
  4.     public FinanceDepartment(String name){  
  5.         super(name);  
  6.     }  
  7.     @Override  
  8.     protected void add(Company company) {  
  9.     }  
  10.     @Override  
  11.     protected void display(int depth) {  
  12.         StringBuilder sb = new StringBuilder("");  
  13.         for (int i = 0; i < depth; i++) {  
  14.             sb.append("-");  
  15.         }  
  16.         System.out.println(new String(sb) + this.getName() ) ;   
  17.     }  
  18.     @Override  
  19.     protected void romove(Company company) {
  20.     }       
  21. }  
  1. public class HRDepartment extends Company {  
  2.     public HRDepartment(){  
  3.     }  
  4.     public HRDepartment(String name){  
  5.         super(name);  
  6.     }  
  7.     @Override  
  8.     protected void add(Company company) {  
  9.     }  
  10.     @Override  
  11.     protected void display(int depth) {  
  12.         StringBuilder sb = new StringBuilder("");  
  13.         for (int i = 0; i < depth; i++) {  
  14.             sb.append("-");   
  15.         }  
  16.         System.out.println(new String(sb) + this.getName() ) ;   
  17.     }  
  18.     @Override  
  19.     protected void romove(Company company) {     
  20.     }  
  21. }  
  1. public class Client {  
  2.     public static void main(String[] args) {  
  3.         Company root = new ConcreteCompany();  
  4.         root.setName("北京總公司");  
  5.         root.add(new HRDepartment("總公司人力資源部"));  
  6.         root.add(new FinanceDepartment("總公司财務部"));  
  7.         Company shandongCom = new ConcreteCompany("山東分公司");  
  8.         shandongCom.add(new HRDepartment("山東分公司人力資源部"));  
  9.         shandongCom.add(new FinanceDepartment("山東分公司賬務部"));  
  10.         Company zaozhuangCom = new ConcreteCompany("棗莊辦事處");  
  11.         zaozhuangCom.add(new FinanceDepartment("棗莊辦事處财務部"));  
  12.         zaozhuangCom.add(new HRDepartment("棗莊辦事處人力資源部"));  
  13.         Company jinanCom = new ConcreteCompany("濟南辦事處");  
  14.         jinanCom.add(new FinanceDepartment("濟南辦事處财務部"));  
  15.         jinanCom.add(new HRDepartment("濟南辦事處人力資源部"));   
  16.         shandongCom.add(jinanCom);  
  17.         shandongCom.add(zaozhuangCom);  
  18.         Company huadongCom = new ConcreteCompany("上海華東分公司");  
  19.         huadongCom.add(new HRDepartment("上海華東分公司人力資源部"));  
  20.         huadongCom.add(new FinanceDepartment("上海華東分公司賬務部"));  
  21.         Company hangzhouCom = new ConcreteCompany("杭州辦事處");  
  22.         hangzhouCom.add(new FinanceDepartment("杭州辦事處财務部"));  
  23.         hangzhouCom.add(new HRDepartment("杭州辦事處人力資源部"));  
  24.         Company nanjingCom = new ConcreteCompany("南京辦事處");  
  25.         nanjingCom.add(new FinanceDepartment("南京辦事處财務部"));  
  26.         nanjingCom.add(new HRDepartment("南京辦事處人力資源部"));  
  27.         huadongCom.add(hangzhouCom);  
  28.         huadongCom.add(nanjingCom);   
  29.         root.add(shandongCom);  
  30.         root.add(huadongCom);  
  31.         root.display(0);  
  32.     }  
  33. }  

運作結果如下:

=====================================================

北京總公司

--總公司人力資源部

--總公司财務部

--山東分公司

----山東分公司人力資源部

----山東分公司賬務部

----濟南辦事處

------濟南辦事處财務部

------濟南辦事處人力資源部

----棗莊辦事處

------棗莊辦事處财務部

------棗莊辦事處人力資源部

--上海華東分公司

----上海華東分公司人力資源部

----上海華東分公司賬務部

----杭州辦事處

------杭州辦事處财務部

------杭州辦事處人力資源部

----南京辦事處

------南京辦事處财務部

------南京辦事處人力資源部

=====================================================

(注:把各種解決方案的實作拿來對比一下更有利于你去了解組合模式的好處!)

五、安全性與透明性

組合模式中必須提供對子對象的管理方法,不然無法完成對子對象的添加删除等等操作,也就失去了靈活性和擴充性。但是管理方法是在Component中就聲明還是在Composite中聲明呢?

一種方式是:在Component裡面聲明所有的用來管理子類對象的方法,以達到Component接口的最大化(如下圖所示)。目的就是為了使客戶看來在接口層次上樹葉和分支沒有差別——透明性。但樹葉是不存在子類的,是以Component聲明的一些方法對于樹葉來說是不适用的。這樣也就帶來了一些安全性問題。

結構型模式:組合模式(Composite Pattern)

另一種方式是:隻在Composite裡面聲明所有的用來管理子類對象的方法(如下圖所示)。這樣就避免了上一種方式的安全性問題,但是由于葉子和分支有不同的接口,是以又失去了透明性。

結構型模式:組合模式(Composite Pattern)

但是在組合模式中,相對于安全性來說,我們比較看中透明性。對于第一種方式中葉子節點内不需要的方法可以使用空處理或者異常報告的方式來解決。

組合Composite模式的優缺點: 

1、使用戶端的調用變得簡單,用戶端可以一緻的使用組合結構或其中單個對象,使用者就不必關系自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼。 

        2、更容易在組合體内加入對象部件. 用戶端不必因為加入了新的對象部件而更改代碼。

        當然組合模式也少不了缺點:組合模式不容易限制組合中的構件。

六、組合模式的優缺點  

1、使用戶端的調用變得簡單,用戶端可以一緻的使用組合結構或其中單個對象,使用者就不必關系自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼。 

        2、更容易在組合體内加入對象部件. 用戶端不必因為加入了新的對象部件而更改代碼。

        當然組合模式也少不了缺點:組合模式不容易限制組合中的構件。

到此為止相信大家已經看懂了上面的例子。但是很多人或許還有疑惑,似乎我們自己很難想象到一個需要使用組合模式的場景,大家不要急,等用到的時候你自然會想到組合模式,我們學習設計模式多是用來儲備知識的,項目開發未必會用到所有的設計模式!

最後,希望大家共同進步!那裡有問題,望指出!

組合Composite模式的優缺點: 

1、使用戶端的調用變得簡單,用戶端可以一緻的使用組合結構或其中單個對象,使用者就不必關系自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼。 

        2、更容易在組合體内加入對象部件. 用戶端不必因為加入了新的對象部件而更改代碼。

        當然組合模式也少不了缺點:組合模式不容易限制組合中的構件。