一、引言
在软件开发中,我们经常会遇到处理简单对象和复合对象的情况,例如操作系统中文件目录的处理,目录可以包含单独的文件,也可以包括文件夹,而文件夹里又包含着文件,如此递归下去或者说是分级数据结构。由于简单对象和复合对象在功能上的区别,导致在操作过程中必须区分简单对象和复合对象,这样导致客户端调用时带来不必要的麻烦,作为客户,希望能够始终如一的对待简单对象和复杂对象。组合模式就是解决这个问题的
二、组合模式
定义:将对象组合成树形结构以表示 "部分 - 整体" 的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
来看看组合模式的基本代码结构
- abstract class Component
- {
- protected string name;
- publicComponent(string name)
- {
- this.name = name;
- }
- public abstract void Add(Component component);
- public abstract void Remove(Component component);
- public abstract voidDisplay(int depth);
- }
- //Leaf在组合中表示叶节点对象
- class Leaf : Component
- {
- publicLeaf(stringname) :base(name) { }
- //由于叶子没有在增加分枝和树叶,所以ADD与Remove方法实现它没有意义;
- //但可以消除叶节点和枝节点在抽象层次的区别,它们具备完全一致的接口
- public override void Add(Component component)
- {
- Console.WriteLine("叶节点不允许添加树枝树叶节点");
- }
- public override voidDisplay(int depth)
- {
- Console.WriteLine(newString('-',depth)+name);
- }
- public override void Remove(Component component)
- {
- Console.WriteLine("由于叶节点没有子节点,这里移除没有任何意义");
- }
- }
- class Composite : Component
- {
- privateList Children = newList();
- publicComposite(stringname) :base(name) { }
- public override void Add(Component component)
- {
- Children.Add(component);
- }
- //显示枝节点名称并对其下级进行遍历
- public override voidDisplay(int depth)
- {
- Console.WriteLine(newString('-',depth)+name);
- foreach(Component componentin Children)
- {
- component.Display(depth +2);
- }
- }
- public override void Remove(Component component)
- {
- Children.Remove(component);
- }
- }
- static voidMain(string[] args)
- {
- Composite root =newComposite("root");
- root.Add(newLeaf("Leaf A"));
- root.Add(newLeaf("Leaf B"));
- Composite comp =newComposite("Composite X");
- comp.Add(newLeaf("Leaf XA"));
- comp.Add(newLeaf("Leaf XB"));
- root.Add(comp);
- Composite comp2 =newComposite("Composite XY");
- comp2.Add(newLeaf("Leaf XYA"));
- comp2.Add(newLeaf("Leaf XYB"));
- comp.Add(comp2);
- root.Add(newLeaf("Leaf C"));
- Leaf leaf =newLeaf("Leaf D");
- root.Add(leaf);
- root.Remove(leaf);
- root.Display(0);
- Console.Read();
- }
结果如下图所示:
透明方式:在 Component 中声明所有管理子对象的方法,这样实现 Component 的子类都有 Add 和 Remove 方法,这样做的好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的接口,但问题也很明显,Leaf 本身没有 Add 和 Remove 方法,实现它是没有意义的
安全方式:在 Component 中不去声明 Add 和 Remove 方法,那么子类 Leaf 就不需要实现它,而是在 Composite 中声明所有管理子类的方法,不过由于不够透明,树叶类和树枝类不具有相同的接口,客户端调用需要相应的判断,带来了不便
下面是大话设计模式中公司管理系统的例子:
- public abstract class Company
- {
- protected string Name;
- publicCompany(string name)
- {
- this.Name = name;
- }
- public abstract void Add(Company company);
- public abstract void Remove(Company company);
- public abstract voidDisplay(int depth);
- public abstract void LineOfDuty();
- }
- //具体公司类 树枝节点
- class ConcreteCompany : Company
- {
- //一个子对象集合 用来存储其下属的枝节点 叶节点
- privateList Children = newList();
- publicConcreteCompany(stringname) :base(name) { }
- public override void Add(Company company)
- {
- Children.Add(company);
- }
- public override voidDisplay(int depth)
- {
- Console.WriteLine(newString('-',depth)+Name);
- foreach(Company comin Children)
- {
- com.Display(depth+2);
- }
- }
- public override void LineOfDuty()
- {
- foreach(Company comin Children)
- {
- com.LineOfDuty();
- }
- }
- public override void Remove(Company company)
- {
- Children.Remove(company);
- }
- }
- //人力资源部类 树叶节点
- class HRDepartment:Company
- {
- publicHRDepartment(stringname) :base(name)
- { }
- public override void Add(Company company)
- {
- }
- public override voidDisplay(int depth)
- {
- Console.WriteLine(newString('-',depth)+Name);
- }
- public override void LineOfDuty()
- {
- Console.WriteLine($"{Name}员工招聘培训管理");
- }
- public override void Remove(Company company)
- {
- }
- }
- //财务部类 树叶节点
- class FinanceDepartment : Company
- {
- publicFinanceDepartment(stringname) :base(name) { }
- public override void Add(Company company)
- {
- }
- public override voidDisplay(int depth)
- {
- Console.WriteLine(newString('-',depth)+Name);
- }
- public override void LineOfDuty()
- {
- Console.WriteLine($"{Name}公司财务收支管理");
- }
- public override void Remove(Company company)
- {
- }
- }
- static voidMain(string[] args)
- {
- ConcreteCompany root =newConcreteCompany("北京总公司");
- root.Add(newHRDepartment("总公司人力资源部"));
- root.Add(newFinanceDepartment("总公司财务部"));
- ConcreteCompany comp =newConcreteCompany("上海华东分公司");
- comp.Add(newHRDepartment("华东分公司人力资源部"));
- comp.Add(newFinanceDepartment("华东分公司财务部"));
- root.Add(comp);
- ConcreteCompany comp1 =newConcreteCompany("南京分公司");
- comp1.Add(newHRDepartment("南京人力资源部"));
- comp1.Add(newFinanceDepartment("南京财务部"));
- comp.Add(comp1);
- ConcreteCompany comp2 =newConcreteCompany("杭州分公司");
- comp2.Add(newHRDepartment("杭州人力资源部"));
- comp2.Add(newFinanceDepartment("杭州财务部"));
- comp.Add(comp2);
- Console.WriteLine("\n结构图");
- root.Display(0);
- Console.WriteLine("\n职责图");
- root.LineOfDuty();
- Console.Read();
- }
运行结果如下图:
使用场景:
1. 想表示对象部分 - 整体层次结构;
2. 希望用户忽略单个对象和组合对象的不同,统一的使用组合结构中的所有对象。
优点:
1. 高层模块不需要关心处理的是单个对象还是复合对象;客户程序可以像处理单个对象一样处理复合对象,将客户程序与复合对象容器结构解耦
2. 更容易往组合对象中添加新的构件,只需要找父节点即可
缺点:设计更加复杂,使得客户需要更多时间理清类之间的层次关系
关于组合模式的学习就到此结束了,希望能够帮到你,若有不足,欢迎斧正,感谢您的阅读。
来源: http://www.cnblogs.com/jdzhang/p/7081521.html