1、什么是组合模式?
组合模式有时候也叫做“整体-部分”模式,它使得类似于树的分级结构中,对于分支和叶节点的处理保持一致,以优化处理递归和分级结构。树结构大家都不陌生,我们电脑里的“资源管理器”就是个典型的树,文件系统由目录和文件组成,每一个目录类似于一个容器,他可以用来装文件,还可以用来装目录。按照这种方式,计算机的文件系统就是以递归结构来组织的,如果你想描述类似于这样的数据结构,可以使用组合模式。
组合模式:将对象组合成树型结构,以表示“整体-部分”关系,组合模式使得客户对单一对象和整体对象的处理保持一致。
2、组合模式中设计的角色:
2.1 Component:抽象组合类,定义了叶子节点和枝节点的行为接口。适当的时候可以实现共有接口的默认行为。
2.2 Leaf:叶子节点,是组合模式中一中没有组合(没有下级)的对象,一般它只实现Component中的部分行为接口。
2.3Composition:枝节点,也就是组合节点,它的下面还有其他的对象,可能是枝节点,也可能是叶节点。一般它需要实现Component中的所有行为接口。
类图:
3、组合模式的核心算法:“递归”
递归:对于问题规模很大,但是处理起来可以将其分为小规模问题来解决并且无论问题规模大小,处理方法都是一致的,这样,我们就可以使用递归。
组合模式中,叶节点的处理很简单,因为叶节点没有子节点,那么也就设计不到添加删除子节点操作,那么其他的操作就是对自己操作,比如,打印,叶节点只需要将自己打印就OK。但是枝节点,因为下面还有子节点,且子节点的类型不定,那么我们就不能针对枝节点来处理,我们应该做的是要对该枝节点的所有子节点做相同的处理,还是说“打印”,如果我们要打印一个枝节点,我们应该将该节点的所有子节点打印出来,这样处理,才能完整的将该节点处理完。
4、示例说明
以一个公司的结构来说,以下是一个公司的结构图,这个图还可以根据需要增加新的子公司,从图中可以分析出,公司结构其实就是公司、财务部门、人力资源部门的一个层级结构,那么对应于组合模式来说,公司或者办事处就是一个Composite,人力资源部门和财务部门就是Leaf.分析完了,将他们落实到代码吧~先来看看对于这个设计的类图:
有了设计类图,写代码就是非常容易的事了:
//抽象公司类,规定了公司结构应该具备的方法 namespace 组合模式____公司结构 { public abstract class Company { protected string name; public Company(string aName) { this.name = aName; } public abstract void add(Company c); public abstract void remove(Company c); public abstract void display(int depth); public abstract void lineOfDuty(); } }
//具体的公司类 -- 组合模式中的整体 namespace 组合模式____公司结构 { public class ConcreteCompany : Company { private List<Company> children = new List<Company>(); public ConcreteCompany(string aName) : base(aName) { } public override void add(Company c) { children.Add(c); } public override void remove(Company c) { if (children.Contains(c)) { children.Remove(c); } } public override void display(int depth) { Console.WriteLine(new string('-',depth)+name); foreach(Company com in children) { com.display(depth+2); } } public override void lineOfDuty() { foreach (Company com in children) { com.lineOfDuty(); } } } }
namespace 组合模式____公司结构 { public class FinanceDepartment : Company { public FinanceDepartment(string aName) : base(aName) { } public override void add(Company c) { } public override void remove(Company c) { } public override void display(int depth) { Console.WriteLine(new string('-',depth)+name); } public override void lineOfDuty() { Console.WriteLine("{0}:公司财务收支管理",name); } } }
namespace 组合模式____公司结构 { public class HRDepartment : Company { public HRDepartment(string aName) : base(aName) { } public override void add(Company c) {} public override void remove(Company c) {} public override void display(int depth) { Console.WriteLine(new string('-',depth)+name); } public override void lineOfDuty() { Console.WriteLine("{0}:员工招聘培训管理",name); } } }
//客户端调用 -- 根据现有公司结构图调用 class Program { static void Main(string[] args) { ConcreteCompany root = new ConcreteCompany("北京总公司"); root.add(new FinanceDepartment("总公司财务部")); root.add(new HRDepartment("总公司人力资源部")); ConcreteCompany branch = new ConcreteCompany("上海华东分公司"); branch.add(new FinanceDepartment("上海华东分公司财务部")); branch.add(new HRDepartment("上海华东分公司人力资源部")); root.add(branch); ConcreteCompany branch1 = new ConcreteCompany("南京办事处"); branch1.add(new FinanceDepartment("南京办事处财务部")); branch1.add(new HRDepartment("南京办事处人力资源部")); branch.add(branch1); ConcreteCompany branch2 = new ConcreteCompany("杭州办事处"); branch2.add(new FinanceDepartment("杭州办事处财务部")); branch2.add(new HRDepartment("杭州办事处人力资源部")); branch.add(branch2); Console.WriteLine("结构图:\n"); root.display(0); Console.WriteLine("职责表:\n"); root.lineOfDuty(); Console.ReadKey(); } } }