组合模式
组合模式属于结构型模式,组合多个对象造成树形构造以示意具备局部-整体关系的层次结构。组合模式让零碎能够对立看待单个对象和组合对象。
组合模式关注那些蕴含叶子构件和容器构件的构造以及它们的组织模式,在叶子构件中不蕴含成员对象,而容器构件中能够蕴含成员对象,这些对象通过递归组合可形成一个树形构造。
组合模式的构造
- Component(形象构建):接口或抽象类,为叶子构件和容器构件提供接口,能够蕴含所有子类共有行为的申明。在形象构件中申明了拜访以及治理它的子构件的办法。
- Leaf(叶子构件):叶子节点对象,叶子节点不存在子节点,它只实现了形象构件中定义的行为。对于其它办法能够采取抛出错误信息来解决。
- Composite(容器构件):容器节点对象,容器节点蕴含子节点,子节点能够是叶子节点也能够是容器节点。它提供一个汇合用来存储子节点,实现了形象构件中申明的所有办法。
组合模式的实现
组合模式的实现关键点在于定义了一个既能够示意叶子构件又能够示意容器构件的形象层,通过对形象层进行编程,毋庸晓得对象具体是什么构件,能够对立进行解决。其次容器对象与形象构件之间是聚合关联关系,在容器对象中既能够蕴含叶子又能够蕴含容器,以此实现递归组合,造成树形构造。
组合模式设计代码如下
//形象层abstract class Component{ public abstract void Add(Component c); public abstract void Remove(Component c); public abstract Component GetChild(int i); public abstract void Operation();}//叶子节点class Leaf : Component{ //实现这些叶子节点不须要的办法减少实现复杂度 public override void Add(Component c) { //...异样解决或谬误提醒 } public override Component GetChild(int i) { //...异样解决或谬误提醒 return null; } public override void Remove(Component c) { //...异样解决或谬误提醒 } public override void Operation() { //具体业务办法的实现 Console.WriteLine("叶子节点具体业务办法的实现"); }}//容器节点class Composite : Component{ private List<Component> m_Childs = new List<Component>(); public override void Add(Component c) { this.m_Childs.Add(c); } public override Component GetChild(int i) { return this.m_Childs[i]; } public override void Remove(Component c) { this.m_Childs.Remove(c); } public override void Operation() { foreach (var item in this.m_Childs) item.Operation(); }}
示例场景
应用组合模式设计一个界面控件库,界面控件分为两类,单元控件和容器空间,单元空间包含文本、按钮等,容器空间包含窗体、面板等。
代码
//形象构件abstract class AbstractComponent{ public abstract void Add(AbstractComponent component); public abstract void Remove(AbstractComponent component); public abstract AbstractComponent GetChild(int index); public abstract void Redraw();}//文本控件(叶子节点)class TextComponent : AbstractComponent{ private string m_Name; public TextComponent(string name) { this.m_Name = name; } public override void Add(AbstractComponent component) { throw new Exception("文本控件不反对该办法"); } public override AbstractComponent GetChild(int index) { throw new Exception("文本控件不反对该办法"); } public override void Remove(AbstractComponent component) { throw new Exception("文本控件不反对该办法"); } public override void Redraw() { Console.WriteLine("重绘------{0}", this.m_Name); }}//按钮控件(叶子节点)class ButtonComponent : AbstractComponent{ private string m_Name; public ButtonComponent(string name) { this.m_Name = name; } public override void Add(AbstractComponent component) { throw new Exception("按钮控件不反对该办法"); } public override AbstractComponent GetChild(int index) { throw new Exception("按钮控件不反对该办法"); } public override void Remove(AbstractComponent component) { throw new Exception("按钮控件不反对该办法"); } public override void Redraw() { Console.WriteLine("重绘------{0}", this.m_Name); }}//窗体控件(容器节点)class FormsComponent : AbstractComponent{ private string m_Name; private List<AbstractComponent> m_Childs; public FormsComponent(string name) { this.m_Name = name; this.m_Childs = new List<AbstractComponent>(); } public override void Add(AbstractComponent component) { this.m_Childs.Add(component); } public override AbstractComponent GetChild(int index) { return this.m_Childs[index]; } public override void Remove(AbstractComponent component) { this.m_Childs.Remove(component); } public override void Redraw() { Console.WriteLine("重绘------{0}", this.m_Name); foreach (var item in this.m_Childs) item.Redraw(); }}//面板控件(容器节点)class PanelComponent : AbstractComponent{ private string m_Name; private List<AbstractComponent> m_Childs; public PanelComponent(string name) { this.m_Name = name; this.m_Childs = new List<AbstractComponent>(); } public override void Add(AbstractComponent component) { this.m_Childs.Add(component); } public override AbstractComponent GetChild(int index) { return this.m_Childs[index]; } public override void Remove(AbstractComponent component) { this.m_Childs.Remove(component); } public override void Redraw() { Console.WriteLine("重绘------{0}", this.m_Name); foreach (var item in this.m_Childs) item.Redraw(); }}//应用static void Main(){ var forms = new FormsComponent("我的窗体"); var panel1 = new PanelComponent("我的界面"); var panel2 = new PanelComponent("子界面"); var text1 = new TextComponent("题目文本"); var text2 = new TextComponent("内容文本"); var button1 = new ButtonComponent("敞开按钮"); var button2 = new ButtonComponent("刷新按钮"); panel2.Add(text1); panel2.Add(text2); panel2.Add(button1); panel1.Add(panel2); panel1.Add(text1); panel1.Add(button1); panel1.Add(button2); forms.Add(panel1); forms.Add(text1); forms.Add(button1); //重绘我的窗体 forms.Redraw(); Console.ReadKey();}
运行后果
通明组合模式与平安组合模式
通明组合模式
上述所讲的是通明组合模式,在通明组合模式中形象构件中申明了子类的所有公共办法,这样做的益处是所有子类都具备雷同的接口,能够将叶子节点与容器节点对立解决。
其毛病是不够平安,因为叶子节点不存在下一层,和容器节点有实质上的差异,因而为叶子节点提供Add、Remove等办法是没有意义的。
平安组合模式
平安组合模式中,形象构件将不再申明任何用于治理成员对象的办法,而是在Composite申明这些办法。对于叶子节点将调用不到这些办法,所以这样做是更平安的。
其毛病也很显著,就是不够通明,因为叶子节点与容器节点存在差别,因而不再可能齐全针对形象层编程,必须区别对待叶子节点与容器节点。
平安组合模式构造
组合模式的长处
- 可能分明地定义分档次的简单对象,示意对象的全副或局部档次,从而应用时能够疏忽档次的差别,不便对整个层次结构进行管制。
- 能够始终地应用一个组合构造或是其中的一个单元,不用关怀解决对象的类型,简化代码。
- 减少新的容器构件与叶子构件都很不便,无需批改现有代码,合乎开闭准则。
- 为树形构造的面向对象提供了一种灵便的解决方案,通过叶子节点和容器节点的递归组合能够造成简单的树形构造,然而对树形构造的管制非常简单。
组合模式的毛病
在应用组合模式时,其叶子节点和容器节点都是具体的实现类,而不是接口,违反了依赖倒置准则。
利用场景
- 在具备整体和局部的构造中,心愿可能疏忽整体与局部的差别进行对立解决。
- 解决树形构造。
- 在一个零碎中可能拆散出叶子节点与容器节点,且它们的类型不固定(后续可能会减少新类型)。