组合模式将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式结构
组合模式非常好的解决了一个整体与部分可以被一致对待的问题。那么,什么叫“整体与部分可以一致对待”呢?
例如:对于一个公司的组织结构的处理:在总公司中包含人力资源部,财务部,分公司。其中人力资源部和财务部是不可再分的,但是分公司下面可以像总公司那样,有自己的人力资源部,财务部,子公司。这是,对于整体的处理和对于部分的处理,是一样 的,既然有重复,那么就可以用相同的方式处理它们。
组合模式这样就定义了包含人力资源部和财务部这些基本对象和分公司,办事处等组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基类对象的地方都可以使用组合对象了。
示例
在学习数据库的时候,里面数据模型叫做层次模型。层次结构中,典型的代表就是文件目录的组织结构。文件夹中包含文件和文件夹,然后文件夹里面又包含文件和文件夹,然后文件夹里面又包含文件和文件夹。。。。。。
如果我们自己写一个文件管理系统的话,就可以用这种结构来模拟文件系统啦~ for example:
namespace 组合模式示例 { //定义抽象的component abstract class ComponentFile { protected string name; //文件夹名称 public ComponentFile(string name) //构造时顺便起个名字 { this.name = name; } public abstract void New(ComponentFile c); //新建 public abstract void Delete(ComponentFile c); //删除 public abstract void ShowFile(int depth); //显示文件结构 } //定义Leaf:文件夹中的文件 class FileInFolder:ComponentFile { public FileInFolder(string name) //调用父类构造方法 : base(name) { } public override void New(ComponentFile c) { Console.WriteLine("非法操作:不能再一个文件里面建立文件夹!"); } public override void Delete(ComponentFile c) { Console.WriteLine("非法操作:此文件里面不包含任何文件夹。"); } public override void ShowFile(int depth) { Console.WriteLine(new string('-', depth) + name); } } //定义Composite:文件夹 class Folder:ComponentFile { //定义一个集合,用来存放此文件夹下的文件夹和文件 private List<ComponentFile> children = new List<ComponentFile>(); public Folder(string name) //调用父类构造方法 : base(name) { } public override void New(ComponentFile c) { children.Add(c); } public override void Delete(ComponentFile c) { children.Remove(c); } public override void ShowFile(int depth) { //首先显示此文件夹名 Console.WriteLine(new string('-', depth) + name); //然后显示此文件夹下的文件夹和文件 foreach (ComponentFile File in children) { File.ShowFile(depth + 10); } } } class Program { static void Main(string[] args) { Console.WriteLine("以下是模仿C盘下部分目录结构:"); Console.WriteLine(""); Folder c=new Folder (@"C:\"); c.New(new FileInFolder (@"temp.txt\")); c.New(new FileInFolder(@"7z.exe")); Folder windows = new Folder(@"windows\"); windows.New(new FileInFolder(@"config.ini\")); windows.New(new FileInFolder(@"explore.exe")); c.New(windows); //c盘下的windows Folder temp = new Folder(@"temp\"); temp.New(new FileInFolder(@"iNodeSetup0\")); c.New(temp); //c盘下的temp c.ShowFile(2); } } }
运行下:
何时使用组合模式?
当发现需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑用组合模式了。