一、概念
①、什么是组合模式?
组合模式又叫部分整体模式,是用于把一组相似的对象当做一个单一的对象。组合模式依据树型结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构性模式,它创建了对象组的树形结构。
②、主要解决的问题?
它在树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
③、如何解决?
树枝和叶子实现统一接口,数值内容组合该接口。
④、何时使用?
1、想要表示对象的部分-整体层次结构(树型结构)。2、希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
⑤、优点和缺点?
优点:高层模块调用简单,节点自由添加。
缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
二、图
①、结构图
②、拓展图
三、代码
①、代码类图
转换为树图
组合模式:客户可以一致地使用组合结构(root3)和单个对象(comp1),其实就是树干上加叶子的问题,用户不用关心到底是处理一个叶节点还是处理一个组合组件。基本对象可以被组合成更复杂的组合对象,而这个组合对象又可以被组合,这样不断地递归下去。
②、代码
class Program
{ //客户端调用
static void Main(string[] args)
{
ConCreteCompany root = new ConCreteCompany("北京总公司"); //找到一颗树根种树:通过枝节点实例化root(北京总公司)对象
root.Add(new HRDepartment("总公司人力资源部")); //主树干上长出了一片叶子:用HRDepartment类实例化一个对象,并将其加到树主干上面
root.Add(new FinanceDepartment("总公司财务部")); //主树干上又长出了一片叶子:用FinanceDepartment类实例化一个对象,并将其加到树的主干上面
ConCreteCompany comp = new ConCreteCompany("上海华东分公司"); //主树干上长出了一个枝干:实例化一个comp对象(上海华东分公司)
comp.Add(new HRDepartment("华东分公司人力资源部")); //在枝干上长出了一片叶子(实例化叶节点)
comp.Add(new FinanceDepartment("华东分公司财务部")); //在枝干上又长出了一片叶子(华东分公司财务部)
root.Add(comp); //主树干上长出了带叶子的枝干:将comp对象添加到主树干上
ConCreteCompany comp1 = new ConCreteCompany("南京办事处");
comp1.Add(new HRDepartment("南京办事处人力资源部"));
comp1.Add(new FinanceDepartment("南京办事处财务部"));
comp.Add(comp1);
ConCreteCompany comp2 = new ConCreteCompany("杭州办事处");
comp2.Add(new HRDepartment("杭州办事处人力资源部"));
comp2.Add(new FinanceDepartment("杭州办事处财务部"));
comp.Add(comp2);
Console.WriteLine("\n结构图:"); //在控制台内写入内容
root.Display(1); //调取主树干的显示方法:传递过去的整数参数为1:表示“-”符号显示一个
Console.WriteLine("\n职责:");
root.LineOfDuty(); //调取主树干的职责方法
Console.Read();
}
}
//公司类 抽象类或接口
abstract class Company
{
protected string name;
public Company (string name) //创建Company的构造函数
{
this.name = name;
}
public abstract void Add(Company c); //创建抽象类的Add()抽象方法
public abstract void Remove(Company c);
public abstract void Display(int depth);
public abstract void LineOfDuty();
}
//具体公司类 实现接口 树枝节点
class ConCreteCompany:Company
{
private List<Company> children = new List<Company>(); //创建一个泛型集合,类型为Company类
public ConCreteCompany(string name):base(name) //继承父类的参数
{ }
public override void Add(Company c) //重写父类的Add()方法
{
children.Add(c); //调取集合的添加Add方法,将输入的内容添加到集合中
}
public override void Remove(Company c) //重写父类Remove()方法
{
children.Remove(c); //移除集合中的内容
}
public override void Display(int depth) //重写父类Display()方法
{
Console.WriteLine(new string ( '-',depth)+name); //在控制台上输入内容:此处的depth代表的是显示几个‘-’符号
foreach (Company component in children ) //遍历children集合(主干树上的内容)
{
component.Display(depth + 2); //调取显示方法,参数为原传入的整数:1加上2,即显示三个“-”符号
}
}
public override void LineOfDuty() //重写抽象类的职责方法
{
foreach (Company component in children ) //遍历children集合,调取每个不同类的职责方法
{
component.LineOfDuty();
}
}
//人力资源部与财务部类 树叶节点
}
class HRDepartment : Company
{
public HRDepartment(string name) : base(name)
{ }
public override void Add(Company c) //叶节点不再长出新节点,所以此处的重写方法是无具体的方法体(透明方式),如果把这个去掉就是(安全方式)了
{ }
public override void Remove(Company c)
{ }
public override void Display(int depth)
{
Console.WriteLine(new string('-', depth) + name);
}
public override void LineOfDuty() //叶节点中的具体实现
{
Console.WriteLine("{0} 员工招聘培训管理", name);
}
}
class FinanceDepartment : Company
{
......(与DRDepartment类似)
}
四、拓展
①、组合模式(很棒的文章)
http://www.cnblogs.com/goodboy-heyang/p/5226090.html
https://www.cnblogs.com/jenkinschan/p/6071933.html
②、for循环与foreach区别
http://www.runoob.com/csharp/csharp-for-loop.html