12.1组合模式定义:
组合模式允许你将对象组合成树型结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
12.2组合模式UML类图:
12.3应用场景:
当我们有数个对象的集合,它们彼此之间有整体/部分的关系,并且想用一致的方式处理它们时,就可以使用组合模式。例如我们的应用程序菜单,每一个菜单项可能是一个普通菜单项,也可能是一个子菜单(里面又包括几个菜单项)。菜单项和子菜单之间的关系就是整体和部分的关系,如果我们想对菜单项和子菜单进行统一的操作,例如显示每个菜单项包括子菜单中的菜单项的名称,利用组合模式,我们可以直接发出显示命令,而不用管是菜单项执行还是子菜单执行。
12.4组合模式分析与实现(c#描述):
public abstract class MenuComponent
{
protected string Caption;//菜单名称
public abstract void ShowMenuCaption();//显示菜单名称
public abstract void Add(MenuComponent aobj_MenuComponent);//增加一个组件
public abstract void Remove(MenuComponent aobj_MenuComponent);//删除一个组件
public abstract MenuComponent GetMenuComponent(int i);//获得组件集合中的一个组件。
}
//菜单项,简单组件,对应于UML类图中的Leaf。
public class MenuItem : MenuComponent
{
public MenuItem(string astg_Caption)
{
this.Caption = astg_Caption;
}
public override void ShowMenuCaption()
{
Console.WriteLine(this.Caption);
}
public override void Add(MenuComponent aobj_MenuComponent)
{
//由于菜单项是简单组件,所以这里没有任何实现。
}
public override void Remove(MenuComponent aobj_MenuComponent)
{
//由于菜单项是简单组件,所以这里没有任何实现。
}
public override MenuComponent GetMenuComponent(int i)
{
//由于菜单项是简单组件,所以这里没有任何实现。
return null;
}
}
//菜单,复杂组件,一个菜单又可以包括多个菜单项,即菜单和菜单项是整体和部分的关系,对应于UML类图中的Component。
public class Menu : MenuComponent
{
private ArrayList ial_ArrayList=new ArrayList();
public Menu(string astg_Caption)
{
this.Caption = astg_Caption;
}
public override void ShowMenuCaption()
{
Console.WriteLine(this.Caption);//把自己的名称显示出来
foreach (MenuComponent lobj_MenuComponent in this.ial_ArrayList)
{
lobj_MenuComponent.ShowMenuCaption();
}
}
public override void Add(MenuComponent aobj_MenuComponent)
{
this.ial_ArrayList.Add(aobj_MenuComponent);
}
public override void Remove(MenuComponent aobj_MenuComponent)
{
this.ial_ArrayList.Remove(aobj_MenuComponent);
}
public override MenuComponent GetMenuComponent(int aint_Index)
{
return (MenuComponent)this.ial_ArrayList[aint_Index];
}
}
//调用类
public class Composite_Test
{
public static void Do()
{
//给“文件”菜单添加子“新建”及“关闭”2个组件。其中“新建”为复杂组件,又包含其它菜单项,“关闭”为简单组件。
MenuComponent lobj_Menu = new Menu("文件");
MenuComponent lobj_NewMenu = new Menu("新建");
lobj_Menu.Add(lobj_NewMenu);
MenuComponent lobj_CloseMenuItem = new MenuItem("关闭");
lobj_Menu.Add(lobj_CloseMenuItem);
//为新建菜单增加子菜单
MenuComponent lobj_ProjectMenuItem = new MenuItem("工程");
lobj_NewMenu.Add(lobj_ProjectMenuItem);
MenuComponent lobj_WebSiteMenuItem = new MenuItem("网站");
lobj_NewMenu.Add(lobj_WebSiteMenuItem);
//显示所有菜单名称 这里因为所有菜单项和菜单都有统一的接口(ShowMenuCaption()),这样客户不需理会所处理的倒底是菜单是菜单项组件,而只需调用抽象中的接口方法即可,即用统一的接口处理简单组件和复杂组件。
lobj_Menu.ShowMenuCaption();
//输出:文件,新建,工程,网站,关闭
}
}
将“客户代码与复杂的对象容器结构”解耦是Composite模式的核心思想,解耦之后,客户代码将与纯粹的抽象接口——而非对象容器的复内部实现结构——发生依赖关系,从而更能“应对变化”。