组合模式(Composite)
定义
组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式有两种形式:透明方式的组合模式和安全方式的组合模式。
类图
描述
Component:它可以是接口或抽象类,为叶子和容器对象声明接口,在该角色中可以包含所有子类共有行为的声明和实现。在抽象类中定义了访问及管理它的子类的方法,如增加子对象、删除子对象、获取子对象等;
Leaf:表示叶子节点对象,叶子节点没有子节点,它实现了在抽象类中定义的行为。对于那些访问及管理子类的方法,可以通过异常等方式进行处理,即在叶子对象中实现子类管理和访问方法时需要提供异常处理或错误提示;
Composite:表示容器节点对象,容器节点包含子节点,其子节点可以是叶子节点,也可以是容器节点,它提供一个集合用于存储子节点,实现了在抽象类中定义的行为,包括那些访问及管理子类的方法,在其业务方法中可以递归调用其子节点的业务方法。
应用场景
树枝有多个叶子和子树枝组成,而子树枝又可以包含多个叶子和子树枝;叶子没有子叶子和子树枝。
一、透明方式的组合模式
类图
描述
透明组合模式中,在抽象类Component中声明了所有用于管理成员对象的方法,如Add()、Remove()以及GetChild()等方法,这样做的好处是确保所有的构件类都有相同的接口。在客户端看来,叶子对象与容器对象所提供的方法是一致的,客户端可以相同地对待所有的对象。
/// <summary> /// 叶子和树枝的声明接口 /// </summary> public abstract class Component { private string name; /// <summary> /// 节点名称 /// </summary> public string Name { get { return name; } } private int depth; /// <summary> /// 节点深度 /// </summary> public int Depth { get { return depth; } } public Component(string name, int depth) { this.name = name; this.depth = depth; } #region 管理成员对象的方法 /// <summary> /// 添加子节点 /// </summary> /// <param name="component"></param> public abstract void Add(Component component); /// <summary> /// 移除子节点 /// </summary> /// <param name="component"></param> public abstract void Remove(Component component); /// <summary> /// 获取子节点 /// </summary> /// <param name="i"></param> /// <returns></returns> public abstract Component GetChild(int i); #endregion /// <summary> /// 子节点操作 /// </summary> public abstract void Display(Component component); } /// <summary> /// 树枝类 /// </summary> public class Composite : Component { /// <summary> /// 子节点集合 /// </summary> private List<Component> children = new List<Component>(); public Composite(string name, int depth) : base(name, depth) { } public override void Add(Component component) { this.children.Add(component); } public override void Remove(Component component) { this.children.Remove(component); } public override Component GetChild(int i) { if (i >= 0 && i < this.children.Count) { return this.children[i]; } else { return null; } } public override void Display(Component component) { foreach (Component c in ((Composite)component).children) { if (c is Composite) { Console.WriteLine(c.Name.PadLeft(c.Depth + c.Name.Length, '-')); Display(c); } else { c.Display(c); } } } } /// <summary> /// 树叶类 /// </summary> public class Leaf : Component { public Leaf(string name, int depth) : base(name, depth) { } public override void Add(Component component) { throw new System.NotImplementedException(); } public override void Remove(Component component) { throw new System.NotImplementedException(); } public override Component GetChild(int i) { throw new System.NotImplementedException(); } public override void Display(Component component) { Console.WriteLine(component.Name.PadLeft(component.Depth + component.Name.Length, '-')); } }
二、安全方式的组合模式
类图
描述
安全组合模式中,在抽象类Component中没有声明任何用于管理成员对象的方法,而是在Composite类中声明并实现这些方法。这种做法是安全的,因为根本不向叶子对象提供这些管理成员对象的方法,对于叶子对象,客户端不可能调用到这些方法.
/// <summary> /// 叶子和树枝的声明接口 /// </summary> public abstract class Component { private string name; /// <summary> /// 节点名称 /// </summary> public string Name { get { return name; } } private int depth; /// <summary> /// 节点深度 /// </summary> public int Depth { get { return depth; } } public Component(string name, int depth) { this.name = name; this.depth = depth; } /// <summary> /// 子节点操作 /// </summary> public abstract void Display(Component component); } /// <summary> /// 树枝类 /// </summary> public class Composite : Component { /// <summary> /// 子节点集合 /// </summary> private List<Component> children = new List<Component>(); public Composite(string name, int depth) : base(name, depth) { } #region 管理成员对象的方法 /// <summary> /// 添加子节点 /// </summary> /// <param name="component"></param> public void Add(Component component) { this.children.Add(component); } /// <summary> /// 移除子节点 /// </summary> /// <param name="component"></param> public void Remove(Component component) { this.children.Remove(component); } /// <summary> /// 获取子节点 /// </summary> /// <param name="i"></param> /// <returns></returns> public Component GetChild(int i) { if (i >= 0 && i < this.children.Count) { return this.children[i]; } else { return null; } } #endregion public override void Display(Component component) { foreach (Component c in ((Composite)component).children) { if (c is Composite) { Console.WriteLine(c.Name.PadLeft(c.Depth + c.Name.Length, '-')); Display(c); } else { c.Display(c); } } } } /// <summary> /// 树叶类 /// </summary> public class Leaf : Component { public Leaf(string name, int depth) : base(name, depth) { } public override void Display(Component component) { Console.WriteLine(component.Name.PadLeft(component.Depth + component.Name.Length, '-')); } }
透明和安全方式组合模式的区别在于是否在抽象类Component中定义子对象的管理行为。