设计模式(十五)组合模式

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

当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式。

ASP.NET 中的 TreeView 控件就是典型的组合模式应用。

 基本代码

  1 // 组合中的对象声明接口
  2 abstract class Component
  3 {
  4   protected string name;
  5 
  6   public Component(string name)
  7   {
  8     this.name = name;
  9   }
 10 
 11   // 增加 / 移除 树叶 或 树枝 的功能
 12   public abstract void Add(Component c);
 13   public abstract void Remove(Component c);
 14   public abstract void Display(int depth);
 15 }
 16 
 17 // 叶子
 18 class Leaf : Component
 19 {
 20   public Leaf(string name) : base(name)
 21   {
 22   }
 23 
 24   // 由于叶子没有再增加分支和树叶,所以 Add 和 Remove 方法实现它没有意义,但这样做可以消除 叶节点 和 枝节点 对象在抽象层次的区别,
 25   // 它们具备完全一致的接口
 26   public override void Add(Component c)
 27   {
 28     Console.WriteLine("Cannot add to a leaf");
 29   }  
 30   public override void Remove(Component c)
 31   {
 32     Console.WriteLine("Cannot remove from a leaf");
 33   }  
 34 
 35   // 叶节点的具体方法,显示其 名称 和 级别
 36   public override void Display(int depth)
 37   {
 38     Console.WriteLine(new String('-', depth) + name);
 39   }  
 40 }
 41 
 42   // 定义 枝节点 行为,用来存储子部件
 43 class Composite : Component
 44 {
 45   // 一个子对象集合用来存储其下属的叶节点 和 枝节点
 46   private List<Component>children = new List<Component>();
 47 
 48   public Composite(string name) : base(name)
 49   {
 50   }
 51 
 52   public override void Add(Component c)
 53   {
 54     children.Add(c);
 55   }
 56 
 57   public override void Remove(Component c)
 58   {
 59     children.Remove(c);
 60   }
 61 
 62   // 显示其枝节点名称,并对其下级进行遍历
 63   public override void Display(int depth)
 64   {
 65     Console.WriteLine(new String('-', depth) + name);
 66 
 67     foreach(Component component in children)
 68     {
 69       component.Display(depth + 2);
 70     }
 71   }
 72 }
 73 
 74 // 客户端
 75 static void Main(string[] args)
 76 {
 77   // 生成树根 root,根上长出两叶 LeafA 和 LeafB
 78   Composite root = new Composite("root");
 79   root.Add(new Leaf("Leaf A"));
 80   root.Add(new Leaf("Leaf B"));
 81 
 82   // 根上长出分枝 Composite X,分枝上也有两叶 LeafXA 和 LeafXB
 83   Composite comp = new Composite("Composite X");
 84   comp.Add(new Leaf("Leaf XA"));
 85   comp.Add(new Leaf("Leaf XB"));
 86 
 87   root.Add(comp);
 88 
 89   // 在 Composite X 上再长出 Composite XY,分枝上也有两叶 LeafXYA 和 LeafXYB
 90   Composite comp2 = new Composite("Composite XY");
 91   comp2.Add(new Leaf("Leaf XYA"));
 92   comp2.Add(new Leaf("Leaf XYB"));
 93   
 94   comp.Add(comp2);
 95 
 96   root.Add(new Leaf("Leaf C"));
 97 
 98   Leaf leaf = new Leaf("Leaf D");
 99   root.Add(leaf);
100   root.Remove(leaf);
101   // 显示大树
102   root.Display(1);
103 
104   Console.Read();
105 }

 【例】公司管理系统 OA

 基本代码

 

  1 // 公司类(抽象类 或 接口)
  2 abstract class Company
  3 {
  4   protected sting name;
  5 
  6   public Company(string name)
  7   {
  8     this.name = name;
  9   }
 10   // 增加
 11   public abstract void Add(Company c);
 12   // 移除
 13   public abstract void Remove(Company c);
 14   // 显示
 15   public abstract void Display(int depth);
 16   // 履行职责
 17   public abstract void LineOfDuty();
 18 }
 19 
 20 // 具体公司类(实现接口 树枝节点)
 21 class ConcreteCompany : Company
 22 {
 23   private List<Company>children = new List<Company>();
 24 
 25   public ConcreteCompany(string name) : base(name)
 26   {
 27   }
 28 
 29   public override void Add(Company c)
 30   {
 31     children.Add(c);
 32   }
 33 
 34   public override void Remove(Company c)
 35   {
 36     children.Remove(c);
 37   }
 38 
 39   public override void Display(int depth)
 40   {
 41     Console.WriteLine(new String('-', depth) + name);
 42 
 43     foreach(Company component in children)
 44     {
 45       component.Display(depth + 2);
 46     }
 47   }
 48 
 49   // 履行职责
 50   public override void LineOfDuty()
 51   {
 52     foreach(Company component in children)
 53     {
 54       component.LineOfDuty();
 55     }
 56   }
 57 }
 58 
 59 // 人力资源部(树叶节点)
 60 class HRDepartment : Company
 61 {
 62   public HRDepartment(string name) : base(name)
 63   {
 64   }
 65 
 66   public override void Add(Company c)
 67   {
 68   }
 69 
 70   public override void Remove(Company c)
 71   {
 72   }
 73 
 74   public override void Display(int depth)
 75   {
 76     Console.WriteLine(new String('-', depth) + name);
 77   }
 78 
 79   // 履行职责
 80   public override void LineOfDuty()
 81   {
 82     Console.WriteLine("{0} 员工招聘培训管理", name);
 83   }  
 84 }
 85 
 86 // 财务部(树叶节点)
 87 class FinanceDepartment : Company
 88 {
 89   public FinanceDepartment(string name) : base(name)
 90   {
 91   }
 92 
 93   public override void Add(Company c)
 94   {
 95   }
 96 
 97   public override void Remove(Company c)
 98   {
 99   }
100 
101   public override void Display(int depth)
102   {
103     Console.WriteLine(new String('-', depth) + name);
104   }
105 
106   // 履行职责
107   public override void LineOfDuty()
108   {
109     Console.WriteLine("{0} 公司财务收支管理", name);
110   }  
111 }
112 
113 // 客户端
114 static void Main(string[] args)
115 {
116   ConcreteCompany root = new ConcreteCompany("北京总公司");
117   root.Add(new HRDepartment("总公司人力资源部"));
118   root.Add(new FinanceDepartment("总公司财务部"));
119 
120   ConcreteCompany comp = new ConcreteCompany("上海华东分公司");
121   comp.Add(new HRDepartment("华东分公司人力资源部"));
122   comp.Add(new FinanceDepartment("华东分公司财务部"));
123   root.Add(comp);
124 
125   ConcreteCompany comp1 = new ConcreteCompany("南京办事处");
126   comp1.Add(new HRDepartment("南京办事处人力资源部"));
127   comp1.Add(new FinanceDepartment("南京办事处财务部"));
128   comp.Add(comp1);
129 
130   Console.WriteLine("\n 结构图:");
131   root.Display(1);
132 
133   Console.WriteLine("\n 职责:");
134   root.LineOfDuty();
135 }

 【总结】

组合模式定义了包含人力资源部和财务部这些基本对象和分公司、办事处等组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象。

组合模式让客户可以一致地使用组合结构和单个对象。

posted @ 2015-06-20 10:08  壬子木  阅读(109)  评论(0)    收藏  举报