组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。
意图
将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
解决问题
它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,
客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。
如何解决
树枝和叶子实现统一的接口,树枝内部结构组合该接口
优点
1.高层模块调用简单
2.节点自由增加
缺点
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒转原则。
C++实现
上图,是一个公司的组织结构图,总部下面有多个子公司,同时总部也有各个部门,子公司下面有多个部门。
UML类图:
Component:
1.为组合中的对象声明接口;
2.在适当的情况下,实现所有类共有接口的缺省行为;
3.声明一个接口用于访问和管理Component的子组件。
Leaf:
1.在组合中表示叶节点对象,叶节点没有子节点;
2.在组合中定义叶节点的行为。
Composite:
1.定义有子部件的那些部件的行为;
2.存储子部件。
Client:
1.通过Component接口操作组合部件的对象。
Code:
//组合模式Composite Pattern
//抽象的部件类描述将来所有部件共有的行为
class Component
{
protected:
string m_strComponent;
public :
Component(string _name)
:m_strComponent(_name)
{}
virtual ~Component()
{}
virtual void Operation() = 0;
virtual void Add(Component* com) = 0;
virtual void Remove(Component* com) = 0;
virtual Component* Getchild(int index) = 0;
virtual string getName()
{
return m_strComponent;
}
virtual void Print() = 0;
};
class Leaf : public Component //树叶结构
{
public:
Leaf(string name)
:Component(name)
{}
void Operation()
{
cout <<"name : " << m_strComponent << endl;
}
void Add(Component* com)
{}
void Remove(Component* com)
{}
Component *GetChild(int index)
{
return NULL;
}
void Print()
{}
};
class Composite : public Component //树枝结构
{
private:
vector<Component *> m_vecComp;
public:
Composite(string name)
:Component(name)
{}
~Composite()
{
vector<Component*>::iterator it = m_vecComp.begin();
while (it != m_vecComp.end())
{
if (*it != NULL)
{
cout << "---delete" << (*it)->getName() + "---" << endl;
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
it = m_vecComp.begin();
}
}
void Operation()
{
cout << "我是 " << m_strComponent << endl;
}
void Add(Component* com)
{
m_vecComp.push_back(com);
}
void Remove(Component* com)
{
for (vector<Component*>::iterator it = m_vecComp.begin(); it != m_vecComp.end();++it)
{
if ((*it)->getName() == com->getName())
{
if (*it != NULL)
{
delete *it;
*it = NULL;
}
m_vecComp.erase(it);
break;
}
}
}
Component* Getchild(int index)
{
if ((size_t)index > m_vecComp.size())
return NULL;
return m_vecComp[index -1];
}
void Print()
{
for (vector<Component*>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
{
cout <<(*it)->getName() << endl;
}
}
};
int test_Composite() //组合模式
{
Component* pNode = new Composite("北京总部 ");
Component * pNodeHr = new Composite("北京人事部");
Component * pNode1 = new Composite("上海分公司");
Component * pNode2 = new Composite("西安分公司");
Component * pNode3 = new Composite("成都分公司");
pNode->Add(pNodeHr);
pNode->Add(pNode1);
pNode->Add(pNode2);
pNode->Add(pNode3);
pNode->Print();
Component* pNode1_Hr = new Composite("上海人事部 ");
Component* pNode1_zj = new Composite("上海质检部 ");
Component* pNode1_kf = new Composite("上海开发部 ");
Component* pNode1_xs = new Composite("上海销售部 ");
pNode1->Add(pNode1_Hr);
pNode1->Add(pNode1_kf);
pNode1->Add(pNode1_xs);
pNode1->Add(pNode1_zj);
pNode1->Print();
//关闭上海质检部
pNode1->Remove(pNode1_zj);
if (pNode != NULL)
{
delete pNode;
pNode = NULL;
}
system("pause");
return 0;
}
使用场景
1.你想表示对象的部分-整体层次结构;
2.希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”
总结
通过上面的简单讲解,我们知道了,组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。现在再结合上面的代码,想想文章开头提出的公司OA系统如何进行设计。
参考:
http://www.jb51.net/article/55878.htm