设计模式(十五)组合模式
组合模式(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 }
【总结】
组合模式定义了包含人力资源部和财务部这些基本对象和分公司、办事处等组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象。
组合模式让客户可以一致地使用组合结构和单个对象。

浙公网安备 33010602011771号