组合模式又叫部分--整体模式,它使得客户程序对单个对象和组合对象使用具有一致性。比如对Word的一个字,一段文字和一篇文章操作是一样的。
组合模式(Composite Pattern)有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。 组合模式让你可以优化处理递归或分级数据结构。有许多关于分级数据结构的例子,使得组合模式非常有用武之地。关于分级数据结构的一个普遍性的例子是你每次使用电脑时所遇到的:文件系统。文件系统由目录和文件组成。每个目录都可以装内容。目录的内容可以是文件,也可以是目录。按照这种方式,计算机的文件系统就是以递归结构来组织的。如果你想要描述这样的数据结构,那么你可以使用组合模式Composite。 定义(GoF《设计模式》):将对象组合成树形结构以表示“部分整体”的层次结构。组合模式使得用户对单个对象和使用具有一致性。 涉及角色: 1.Component 是组合中的对象声明接口,在适当的情况下,实现所有类共有接口的默认行为。声明一个接口用于访问和管理Component子部件。 2.Leaf 在组合中表示叶子结点对象,叶子结点没有子结点。 3.Composite 定义有枝节点行为,用来存储子部件,在Component接口中实现与子部件有关操作,如增加(add)和删除(remove)等。 适用性 以下情况下适用Composite模式: 1.你想表示对象的部分-整体层次结构 2.你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。 总结 组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素。 如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。。文件和目录都执行相同的接口,这是组合模式的关键。通过执行相同的接口,你就可以用相同的方式对待文件和目录,从而实现将文件或者目录储存为目录的子级元素。
假设某公司组织结构为:
--总经理
----技术部门经理
-------开发人员A
-------开发人员B
----销售部门经理
-------销售人员C
-------销售人员D
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Component
{
public:
string m_strName;
Component(string strName)
{
this->m_strName=strName;
}
virtual void add(Component *com)=0;
virtual void dispaly(int nDepth)=0;
};
class Leaf:public Component
{
public:
Leaf(string strName):Component(strName){/*this->m_strName=strName;*/}
virtual void add(Component *com){cout<<"can't add leaf"<<endl;}
virtual void dispaly(int nDepth)
{
string strTemp;
for(int i=0;i<nDepth;i++)
{
strTemp+="-";
}
strTemp+=this->m_strName;
cout<<strTemp<<endl;
}
};
class Composite:public Component
{
public:
Composite(string strName):Component(strName){}
virtual void add(Component *com){m_pCom.push_back(com);}
virtual void dispaly(int nDepth)
{
string strTemp;
for(int i=0;i<nDepth;i++)
{
strTemp+="-";
}
strTemp+=this->m_strName;
cout<<strTemp<<endl;
vector<Component*>::iterator it=m_pCom.begin();
while(it!=m_pCom.end())
{
(*it)->dispaly(nDepth+2);
++it;
}
}
private:
vector<Component*>m_pCom;
};
void main()
{
Composite *p=new Composite("总经理");
Composite *pM=new Composite("技术部门经理");
p->add(pM);
pM->add(new Leaf("开发人员A"));
pM->add(new Leaf("开发人员B"));
Composite *pS=new Composite("销售部门经理");
p->add(pS);
pS->add(new Leaf("销售人员C"));
pS->add(new Leaf("销售人员D"));
p->dispaly(1);
};
组合模式,将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
二、解决的问题(What To Solve)
解决整合与部分可以被一致对待问题。
三、组合模式分析(Analysis)
1、组合模式结构
Component类:组合中的对象声明接口,在适当情况下,实现所有类共有接口的行为。声明一个接口用于访问和管理Component的子部件
Leaf类:叶节点对象,叶节点没有子节点。由于叶节点不能增加分支和树叶,所以叶节点的Add和Remove没有实际意义。
有叶节点行为,用来存储叶节点集合
Composite类:实现Componet的相关操作,比如Add和Remove操作。
children:用来存储叶节点集合
2、源代码
1、抽象类Component |
public abstract class Component { protected string name;
public Component(string name) { this.name = name; }
public abstract void Add(Component c); public abstract void Remove(Component c); public abstract void Diaplay(int depth); } |
2、叶子节点Leaf 继承于Component |
public class Leaf:Component {
public Leaf(string name) :base(name) {
}
public override void Add(Component c) { Console.WriteLine("不能向叶子节点添加子节点"); }
public override void Remove(Component c) { Console.WriteLine("叶子节点没有子节点"); }
public override void Diaplay(int depth) { Console.WriteLine(new string('-',depth)+name); } } |
3、组合类Composite继承于Component,拥有枝节点行为 |
public class Composite : Component {
List<Component> children;
public Composite(string name) :base(name) { if (children == null) { children = new List<Component>(); } }
public override void Add(Component c) { this.children.Add(c); }
public override void Remove(Component c) { this.children.Remove(c); }
public override void Diaplay(int depth) { Console.WriteLine(new String('-',depth)+name); foreach (Component component in children) { component.Diaplay(depth + 2); } } }
|
4、客户端代码 |
static void Main(string[] args) { Composite root = new Composite("根节点root"); root.Add(new Leaf("根上生出的叶子A")); root.Add(new Leaf("根上生出的叶子B"));
Composite comp = new Composite("根上生出的分支CompositeX"); comp.Add(new Leaf("分支CompositeX生出的叶子LeafXA")); comp.Add(new Leaf("分支CompositeX生出的叶子LeafXB"));
root.Add(comp);
Composite comp2 = new Composite("分支CompositeX生出的分支CompositeXY"); comp2.Add(new Leaf("分支CompositeXY生出叶子LeafXYA")); comp2.Add(new Leaf("分支CompositeXY生出叶子LeafXYB"));
comp.Add(comp2);
root.Add(new Leaf("根节点生成的叶子LeafC")); Leaf leafD = new Leaf("leaf D"); root.Add(leafD); root.Remove(leafD); root.Diaplay(1); Console.Read(); } |
3、程序运行结果
四.案例分析(Example)
1、场景
假设公司组织结构为:
--总结理
----技术部门经理
------开发人员A
------开发人员B
----销售部门经理
总经理直接领导技术部经理和销售部经理,技术部经理直接领导开发人员A和开发人员B。销售部经理暂时没有直接下属员工,随着公司规模增大,销售部门会新增销售员工。计算组织结构的总工资状况。
如下图所示
IComponent接口:此接口包括了Component和Composite的所有属性,公司每个角色都有职称Title和工资待遇Salary,Add方法把员工加入到组织团队中。
Component叶子节点:叶节点没有子节点,Add方法实现没有任何意义。
Composite组合类:此类有一个员工集合_listEmployees,Add方法向此集合中添加员工信息。
GetCost方法获得组织结构中的工资待遇总和
2、代码
1、接口IComponent |
8. |
2、叶节点Component |
22.
|
3、组合类Composite |
1. public class Composite : IComponent 2. { 3. private List<IComponent> _listEmployees; 4. 5. public string Title { get; set; } 6. public decimal Salary { get; set; } 7. 8. public Composite(string Title, decimal Salary) 9. { 10. this.Title = Title; 11. this.Salary = Salary; 12. _listEmployees = new List<IComponent>(); 13. } 14. 15. public void Add(IComponent comp) 16. { 17. _listEmployees.Add(comp); 18. } 19. 20. public void GetCost(ref decimal salary) 21. { 22. salary += this.Salary; 23. 24. foreach (IComponent component in this._listEmployees) 25. { 26. component.GetCost(ref salary); 27. } 28. } 29. } |
4、客户端代码 |
33. |