设计模式-组合模式
定义:组合模式也叫部分-整体模式,将对象组合成树形结构以表示 “部分-整体” 的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
一个公司的人员(部分员工)组成结构如下
如上的树形结构图展示了一个公司的人员结构,公司最高指挥者是CEO,往下一层是研发经理、销售经理、财务经理、人事部经理等等,根据部门不同,经理下还有组长,组长下还有具体员工。
从该属性结构分析,有两种不同的节点
组合节点:有子节点的节点 (如上 CEO、研发经理)
叶子节点:没有子节点的节点 (如上 研发组员 A,销售员F)
通过组合节点和子节点,能够无限递归迭代的拓扑树形结构。
组合模式的角色结构图如下
Component 抽象构件角色
定义组合对象的共有方法和属性,可以定义一些默认的行为或属性
Leaf 叶子构件
叶子对象,其下没有其他的分支,是最小的单元
Composite 树枝(组合)构件
树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构
下面将公司员工结构通过代码实现
Component 抽象构件角色
// 员工:Component
// 员工接口,抽象构件角色
public interface IEmployee
{
string Info { get; set; }
// 设置员工信息
void SetInfo(string info);
// 获取员工信息
string GetInfo();
// 工作
void Working();
}
Composite 树枝(组合)构件
// 领导者:Composite
// 组合构件,可以添加组合构件、叶子构件作为子节点
public class Leader : IEmployee
{
private List<IEmployee> employeeList = new List<IEmployee>();
public void AddEmployee(IEmployee employee)
{
employeeList.Add(employee);
}
public void RemoveEmployee(IEmployee employee)
{
employeeList.Remove(employee);
}
public IEmployee GetEmployee(int index)
{
return employeeList[index];
}
public string Info { get; set; }
// 员工信息
public void SetInfo(string info)
{
Info = info;
}
// 获取员工信息
public string GetInfo()
{
return Info;
}
// 工作
public void Working()
{
StringBuilder sb = new StringBuilder();
sb.Append(Info + string.Format(" 开始工作了我需要管理{0}个组员", employeeList.Count));
foreach(var employee in employeeList)
{
sb.Append(employee.Info + " ");
}
sb.AppendLine();
sb.AppendLine();
Console.WriteLine(sb.ToString());
foreach(var employee in employeeList)
{
employee.Working();
}
}
}
Leaf 叶子构件
// 组员:Leaf 叶子构件
// 不能添加叶子节点了
public class Members : IEmployee
{
public string Info { get; set; }
// 员工信息
public void SetInfo(string info)
{
Info = info;
}
// 获取员工信息
public string GetInfo()
{
return Info;
}
// 工作
public void Working()
{
string msg = string.Format("{0} 开始工作了,我要认真完成我的工作 \n", Info);
Console.WriteLine(msg);
}
}
代码调用如下
class Corp
{
public Corp()
{
Leader ceo = new Leader();
ceo.SetInfo("CEO");
#region 研发部
Leader developLeader = new Leader();
developLeader.SetInfo("研发经理");
Leader developGroup1 = new Leader();
developGroup1.SetInfo("研发组长一");
Leader developGroup2 = new Leader();
developGroup2.SetInfo("研发组长二");
Members develop1 = new Members();
develop1.SetInfo("研发组员A");
Members develop2 = new Members();
develop2.SetInfo("研发组员B");
Members develop3 = new Members();
develop3.SetInfo("研发组员C");
Members develop4 = new Members();
develop4.SetInfo("研发组员D");
Members develop5 = new Members();
develop5.SetInfo("研发组员E");
// 组合节点添加子节点
// 将研发组长一、研发组长二 添加给 研发经理
developLeader.AddEmployee(developGroup1);
developLeader.AddEmployee(developGroup2);
// 将研发组员A、研发组员B、研发组员C 添加给 研发组长一
developGroup1.AddEmployee(develop1);
developGroup1.AddEmployee(develop2);
developGroup1.AddEmployee(develop3);
// 将研发组员D、研发组员E、 添加给 研发组长二
developGroup2.AddEmployee(develop4);
developGroup2.AddEmployee(develop5);
#endregion
#region 销售部
Leader saleLeader = new Leader();
saleLeader.SetInfo("销售经理");
Members sale1 = new Members();
sale1.SetInfo("销售员F");
Members sale2 = new Members();
sale2.SetInfo("销售员G");
Members sale3 = new Members();
sale3.SetInfo("销售员H");
// 将 销售员F、销售员G、销售员H 添加给 销售经理
saleLeader.AddEmployee(sale1);
saleLeader.AddEmployee(sale2);
saleLeader.AddEmployee(sale3);
#endregion
// 将 研发经理、销售经理 添加给 CEO
ceo.AddEmployee(developLeader);
ceo.AddEmployee(saleLeader);
// CEO 号召大家一起工作啦
ceo.Working();
}
}
CEO 是整棵树的跟节点,运行时只需要调用 跟节点的执行方法 Working() 就可以调动整棵树所有节点的执行。
运行结果如下
如果结构比较复杂,可以使用配置文件动态的创建树形结构
优点:
(1)高层模块调用简单,一棵树的所有节点都是 Component,局部和整体对调用者来说没有任何区别,也就是说,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码
(2)节点自由添加、删除,容易扩展,符合开闭原则,易于维护
缺点:
(1) 设计变得更加抽象,对象的业务规则如果比较复杂,则实现组合模式难度比较大