組合模式概述 定義:組合多個對象形成樹形結構以表示具有部分-整體關係的層次結構。組合模式讓客戶端可以統一對待單個對象和組合對象。又被成為“部分-整體”(Part-Whole)模式,屬於對象結構性模式 定義什麼的,最枯燥了。簡單的來說,就如我們滑鼠右擊新建文件夾一樣,在一個磁碟里,我們可以新建一個文件 ...
- 組合模式概述
定義:組合多個對象形成樹形結構以表示具有部分-整體關係的層次結構。組合模式讓客戶端可以統一對待單個對象和組合對象。又被成為“部分-整體”(Part-Whole)模式,屬於對象結構性模式
定義什麼的,最枯燥了。簡單的來說,就如我們滑鼠右擊新建文件夾一樣,在一個磁碟里,我們可以新建一個文件夾A,也可以新建某個類型的文件a,A和a都在同一目錄下,當然,我們也可以點擊進入文件夾A,在A中新建新的文件夾B,也可以在A中新建文件b。只要是文件夾,就可以在裡面繼續新建文件夾和文件,而文件則只能用來放數據,不能在新建了。
當然,也可以通過win+r調出運行,輸入cmd(commmand),進入你想查看文件的磁碟,輸入tree命令,就可以結構性的查看所有文件。在上述圖中可以看出文件結構就如同一棵樹,有文件夾,有文件,我們把文件成為葉子(Laef),因為文件不能再展開了,就如樹形結構中葉子是最底層了;把文件夾稱為容器(Container),因為文件夾里既可以文件夾,又可以放文件。當想要查看一個磁碟的所有文件時,可以使用DFS(深度優先搜索)即遞歸的對每個文件夾進行同樣的搜索,一條路走到底,當訪問到葉子結點時,再退回去訪問別的結點。
- 組合模式結構和實現
- Component(抽象構件):它可以是介面或抽象類,為葉子構件和容器構件對象聲明介面。定義了訪問管理它的子構件的方法,就是對一個子構件該有的操作都應該在這聲明,如創建子構件,刪除子構件,打開子構件,重命名子構件,複製子構件.......
- Leaf(葉子構件):代表一個文件,實現在Component中的行為,即對文件的操作,可以是讀文件,寫文件,刪除文件,複製文件......
- Composite(容器構件):代表一個文件夾,它提供一個集合放子節點,可以是文件夾,也可以是文件,所以它有一個聚合箭頭指向Component,代表可以遞歸的創建構件
1 abstract class Component 2 { 3 public abstract void Add(Component c); 4 public abstract void Remove(Component c); 5 public abstract Component GetChild(int i); 6 public abstract void Operation(); 7 } 8 class Leaf : Component 9 { 10 public override void Add(Component c) 11 { 12 //throw new NotImplementedException();//這裡是報錯,葉子文件沒有此方法的 13 } 14 15 public override void Remove(Component c) 16 { 17 //throw new NotImplementedException();//同上 18 } 19 20 public override Component GetChild(int i ) 21 { 22 //throw new NotImplementedException();//同上 23 return null; 24 } 25 26 public override void Operation() 27 { 28 //對文件的可執行方法 29 } 30 } 31 class Composite : Component 32 { 33 private IList<Component> list = new List<Component>();//這裡通鏈表容器存放文件夾 34 public override void Add(Component c) 35 { 36 list.Add(c); 37 } 38 39 public override void Remoce(Component c) 40 { 41 list.Remove(c); 42 } 43 44 public override Component GetChild(int i ) 45 { 46 return (Component)list(c); 47 } 48 49 public override void Operation() 50 { 51 //遞歸實現容器中的對文件的方法 52 foreach(Component child in list) 53 { 54 (Component)child.Operation(); 55 } 56 } 57 }
- 組合模式的應用
教育機構的OA系統要給各辦公室下發公文(IssuedBytheOfficeDoucument),採用組合模式模擬實現
分析:從圖中可以看出,北京總部,湖南分校,長沙叫教學點,湘潭教學點這幾個有子構件,所以它們為文件容器,而教務辦公室,行政辦公室即為葉子,當然,每個葉子是不同的,要區別開。因此我們定義一個抽象機構類(AbstractInstitutions),其中聲明Add,Remove,GetChild和IssuedBytheOfficeDoucument方法。
1 abstract class AbstractInstitutions//Component 2 { 3 public abstract void Add(AbstractInstitutions institutions); 4 public abstract void Remove(AbstractInstitutions institutions); 5 public abstract AbstractInstitutions GetChild(int i); 6 public abstract void IssuedBytheOfficeDoucument(); 7 }View Code
教務辦公室,有自己的名字,即哪一個教務辦公室,它只能收到下發的公文
1 class AcademicAffairsOffice : AbstractInstitutions//Leaf 教務辦公室 2 { 3 private string name; 4 public AcademicAffairsOffice(string name) 5 { 6 this.name = name; 7 } 8 public override void Add(AbstractInstitutions institutions) 9 { 10 Console.WriteLine("Can't realize this method!!!"); 11 } 12 13 public override void Remove(AbstractInstitutions institutions) 14 { 15 Console.WriteLine("Can't realize this method!!!"); 16 } 17 18 public override AbstractInstitutions GetChild(int i) 19 { 20 Console.WriteLine("Can't realize this method!!!"); 21 return null; 22 } 23 24 public override void IssuedBytheOfficeDoucument() 25 { 26 Console.WriteLine("issued by the office doucument to the {0}",name); 27 } 28 }View Code
行政辦公室和教務辦公室類似的實現
1 class AdministrationOffice : AbstractInstitutions//Leaf 行政辦公室 2 { 3 private string name; 4 public AdministrationOffice(string name) 5 { 6 this.name = name; 7 } 8 9 public override void Add(AbstractInstitutions institutions) 10 { 11 Console.WriteLine("Can't realize this method!!!"); 12 } 13 14 public override void Remove(AbstractInstitutions institutions) 15 { 16 Console.WriteLine("Can't realize this method!!!"); 17 } 18 19 public override AbstractInstitutions GetChild(int i) 20 { 21 Console.WriteLine("Can't realize this method!!!"); 22 return null; 23 } 24 25 public override void IssuedBytheOfficeDoucument() 26 { 27 Console.WriteLine("issued by the office doucument to the {0}", name); 28 } 29 }View Code
容器類中實現抽象構件中的方法,並且要向下屬機構下發公文
1 class TeachArea : AbstractInstitutions//Composite //教學點 2 { 3 private string name; 4 private IList<AbstractInstitutions> AreaList = new List<AbstractInstitutions>(); 5 6 public TeachArea(String name) 7 { 8 this.name = name; 9 } 10 11 public override void Add(AbstractInstitutions institutions) 12 { 13 AreaList.Add(institutions); 14 } 15 16 public override void Remove(AbstractInstitutions institutions) 17 { 18 AreaList.Remove(institutions); 19 } 20 21 public override AbstractInstitutions GetChild(int i) 22 { 23 return (AbstractInstitutions)AreaList[i]; 24 } 25 26 public override void IssuedBytheOfficeDoucument() 27 { 28 Console.WriteLine("Issue official documents to the {0}", name); 29 foreach (Object obj in AreaList) 30 { 31 ((AbstractInstitutions)obj).IssuedBytheOfficeDoucument(); 32 } 33 } 34 }View Code
Program中,要將所有的機構創建出來,並一一Add到對應的容器中,最後有由北京總部向下發送公文
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 AbstractInstitutions BeijingHeadquarters; 6 BeijingHeadquarters = new TeachArea("BeijingHeadquarters"); 7 8 AbstractInstitutions BeijingAcademicAffairsOffice; 9 BeijingAcademicAffairsOffice = new AcademicAffairsOffice("BeijingAcademicAffairsOffice"); 10 AdministrationOffice BeijingAdministrationOffice; 11 BeijingAdministrationOffice = new AdministrationOffice("BeijingAdministrationOffice"); 12 13 AbstractInstitutions HunanPartition; 14 HunanPartition = new TeachArea("HunanPartition"); 15 16 AbstractInstitutions HunanChangshaArea; 17 HunanChangshaArea = new TeachArea("HunanChangshaArea"); 18 19 AbstractInstitutions HunanXiangtanArea; 20 HunanXiangtanArea = new TeachArea("HunanXiangtanArea"); 21 22 AbstractInstitutions HunanAcademicAffairOffice; 23 HunanAcademicAffairOffice = new AcademicAffairsOffice("HunanAcademicAffairOffice"); 24 AbstractInstitutions HunanAdministrationOffice; 25 HunanAdministrationOffice = new AdministrationOffice("HunanAdministrationOffice"); 26 27 Console.WriteLine(); 28 AbstractInstitutions ChangshaAcademicAffairOffice; 29 ChangshaAcademicAffairOffice = new AcademicAffairsOffice("ChangshaAcademicAffairOffice"); 30 31 AbstractInstitutions ChangshaAdministrationOffice; 32 ChangshaAdministrationOffice = new AdministrationOffice("ChangshaAdministrationOffice"); 33 AbstractInstitutions XiangtanAcademicAffairOffice; 34 XiangtanAcademicAffairOffice = new AcademicAffairsOffice("XiangtanAcademicAffairOffice"); 35 36 AbstractInstitutions XiangtanAdministrationOffice; 37 XiangtanAdministrationOffice = new AdministrationOffice("XiangtanAdministrationOffice"); 38 39 HunanChangshaArea.Add(ChangshaAcademicAffairOffice); 40 HunanChangshaArea.Add(ChangshaAdministrationOffice); 41 42 HunanXiangtanArea.Add(XiangtanAcademicAffairOffice); 43 HunanXiangtanArea.Add(XiangtanAdministrationOffice); 44 45 HunanPartition.Add(HunanChangshaArea); 46 HunanPartition.Add(HunanXiangtanArea); 47 HunanPartition.Add(HunanAcademicAffairOffice); 48 HunanPartition.Add(HunanAdministrationOffice); 49 50 BeijingHeadquarters.Add(BeijingAcademicAffairsOffice); 51 BeijingHeadquarters.Add(BeijingAdministrationOffice); 52 BeijingHeadquarters.Add(HunanPartition); 53 BeijingHeadquarters.IssuedBytheOfficeDoucument(); 54 } 55 }View Code
運行結果:
- 透明組合模式和安全組合模式
- 透明組合模式
在Component中聲明所有的方法,這樣滿足了一致性的原則,即對葉子和容器對象都是一樣的處理,不需用再去判斷,這個對象是葉子還是容器啊,如果是容器,可以實現哪些方法,如果是葉子,又只能實現哪些方法。這些判斷都不需要。但是,由於葉子也繼承了Component的方法,因此不安全,葉子對象不能調用Add,Remove,GetChild的方法,如果運行時調用,會出錯,因此要提供錯誤處理代碼(如上述例子中的( Console.WriteLine("Can't realize this method!!!");
- 安全組合模式
Component中沒有聲明任何方法,而是在Composite中聲明並實現,這樣做不會因為Leaf調用錯誤的方法而報錯,但缺點是不夠透明,即要區別的對待葉子構件和容器構件,但是日常使用是很多的,畢竟安全的往往好很多
上面的例子使用了透明組合模式。
- 組合模式的優缺點和適用環境
- 組合模式的優點:
- 可以清楚的定義分層次的複雜對象,表示對象的全部會部分層次,讓客戶忽略層次的差異,方便控制
- 客戶端可以一致性的使用一個組合結構或其中單個對象,不必關心處理的是單個對象(葉子文件)還是組合結構(文件夾容器),簡化了客戶端代碼
- 增加新的容器構件和葉子構件很方便
- 為樹型結構的面向對象實現了一種靈活的解決方案
- 組合模式的缺點:
- 在增加新的構件時很難對容器中的構件類型進行控制。如果我希望文件夾里只能放文件時,則需要複雜的實現過程來實現
- 組合模式的適用環境
- 在具有整體和部分層次的結構中,希望通過一種方式忽略整體與部分的差異,一致的對待它們
- 在一個使用面向對象語言開發的系統中要處理一個樹形結構時
- 在一個系統總能夠分離出葉子和容器對象,而且它們的類型不固定,需要增加一些新的類型