首页 > 代码库 > 11 组合模式

11 组合模式

组合模式(Composite)定义:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

UML类图如下:

技术分享

 

比如《大话》中举的例子,公司总部在北京,然后在南京、杭州设有办事处,总公司和分支办事处都有相似的组织结构,比如都有人力资源部、财务部等。如下图:

技术分享

再有HeadFirst举的关于菜单的例子,如下图:

技术分享

如果程序需要表达上面例子中的公司层级组织或是菜单层级的结构,就可以采用组合模式。

组合模式能让我们用树形方式创建对象的结构,树里面包含了组合以及个别的对象。使用组合结构,我们能把相同得操作应用在组合和个别对象上。换句话说,在大对数大多数情况下,我们可以忽略对象组合和个别对象之间的差别。这为编程带了了极大的方便。

关于餐厅菜单的代码如下:

MenuComponent类:

 

技术分享
 1 class MenuComponent 
 2     {
 3         public virtual void Add(MenuComponent menuComponent)
 4         {
 5             throw new NotImplementedException();
 6         }
 7         public virtual void Remove(MenuComponent menuComponent)
 8         {
 9             throw new NotImplementedException();
10         }
11         public virtual MenuComponent GetChild(int i)
12         {
13             throw new NotImplementedException();
14         }
15         public virtual string GetName()
16         {
17             throw new NotImplementedException();
18         }
19         public virtual string GetDescription()
20         {
21             throw new NotImplementedException();
22         }
23         public virtual double GetPrice()
24         {
25             throw new NotImplementedException();
26         }
27         public virtual bool IsVegetarian()
28         {
29             throw new NotImplementedException();
30         }
31         public virtual void Print()
32         {
33             throw new NotImplementedException();
34         }
35     }
View Code

 

 所有组件都必须继承MenuComponent类,类中的虚方法都默认抛出异常,子类根据需要进行重写。

MenuItem类(比如午餐菜单中的某一道具体的菜):

技术分享
 1  class MenuItem : MenuComponent
 2     {
 3         string name;
 4         string description;
 5         bool isVegetarian;
 6         double price;
 7 
 8         public MenuItem(string name, string description, bool isVegetarian, double price)
 9         {
10             this.name = name;
11             this.description = description;
12             this.isVegetarian = isVegetarian;
13             this.price = price;
14         }
15 
16         public override string GetName()
17         {
18             return name;
19         }
20         public override string GetDescription()
21         {
22             return description;
23         }
24         public override double GetPrice()
25         {
26             return price;
27         }
28         public override bool IsVegetarian()
29         {
30             return isVegetarian;
31         }
32         public override void Print()
33         {
34             Console.Write("-----Name:{0}--Price:{1}--Description:{2}--{3}", name, price, description, (isVegetarian ? "V" : ""));
35             Console.WriteLine();
36         }
37     }
View Code

 

 Menu类(比如煎饼屋菜单、午餐菜单):

技术分享
 1 class Menu : MenuComponent
 2     {
 3         List<MenuComponent> listMenuComponent = new List<MenuComponent>();
 4         string name;
 5         string description;
 6 
 7         public Menu(string name, string description)
 8         {
 9             this.name = name;
10             this.description = description;
11         }
12 
13         public override void Add(MenuComponent menuComponent)
14         {
15             listMenuComponent.Add(menuComponent);
16         }
17         public override void Remove(MenuComponent menuComponent)
18         {
19             listMenuComponent.Remove(menuComponent);
20         }
21         public override MenuComponent GetChild(int i)
22         {
23             return listMenuComponent[i];
24         }
25         public override string GetName()
26         {
27             return name;
28         }
29         public override string GetDescription()
30         {
31             return description;
32         }
33         public override void Print()
34         {
35             Console.WriteLine("--Name:{0}--Description:{1}", name, description);
36             foreach (var item in listMenuComponent)
37             {
38                 item.Print();
39             }
40         }
41     }
View Code

 

 Menu类不必重写GetPrice()和IsVegetarian()方法,而且Menu类的Print()类比较特殊,需要遍历内部的所有MenuItem类并逐个打印。

 

11 组合模式