背景:
类似:办公oa系统,卖电脑的商家,可以单独卖配件,也可以整机卖。复制文件:一个一个复制,或是复制整个文件夹。文本编辑:单独的改变字体色号,或是整段文字。
即整体与部分可以被一致对待的问题。
总部的财务也可以使用分部的财务。
组合模式(Composite)
将对象组合成树形结构以表示“部分——整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
UML结构图
1.透明方式与安全方式
树可能有无数分支,但只需要反复用Composite就可以实现树状结构了。
Leaf类中也有Add 和Remove这种方式叫透明方式,也就是说在Component中声明的所有用来管理子对象的方法,其中包括Add 和Remove等。这样实现Component接口的所有子类都有了该功能。好处是叶节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但问题也明显,Leaf类中本身不具备Add 和Remove方法的功能,实现它没有意义。
如果不希望再leaf类中不用Add 和Remove。需要安全方式,即在Component接口中不去声明Add 和Remove,子类就无需去实现,而是在Composite声明所有用来管理子类对象的方法,这样就不会出现该问题。不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。
2. 何时使用:发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,剋有考虑使用组合模式。
C++实现代码
//公司类 抽象类或者接口
class Company {
protected:
string m_name;
public:
Company(string str)
{
m_name = str;
}
virtual void Add(Company* c) = 0;
virtual void Remove(Company* c) = 0;
virtual void Display(int depth) = 0;
virtual void lineOfDuty()= 0; // 履行职责
};
//具体公司实现接口 树枝节点
class ConcreteCompany : public Company {
private:
vector<Company*> m_list;
public:
ConcreteCompany(string name) :Company(name)
{
}
void Add(Company* c)
{
m_list.push_back(c);
}
void Remove(Company* c)
{
m_list.pop_back();
}
void Display(int depth)
{
string str = "+";
for (int i = 1; i < depth; i++)
{
str.append("+");
}
cout << str << m_name << endl;
for (int i = 0; i < m_list.size(); i++)
{
m_list.at(i)->Display(depth+2);
}
}
void lineOfDuty()
{
for (int i = 0; i < m_list.size(); i++)
{
m_list.at(i)->lineOfDuty();
}
}
};
//人力资源部 与财务部 树叶节点
class HRDepartment :public Company {
public:
HRDepartment(string name) :Company(name)
{
}
void Add(Company* c)
{
}
void Remove(Company* c)
{
}
void Display(int depth)
{
string str = "+";
for (int i = 1; i < depth; i++)
{
str.append("+");
}
cout << str << m_name << endl;
}
void lineOfDuty()
{
cout << m_name << ":员工招聘 " << endl;
}
};
class FinanceDepartment :public Company {
public:
FinanceDepartment(string name) :Company(name)
{
}
void Add(Company* c)
{
}
void Remove(Company* c)
{
}
void Display(int depth)
{
string str = "+";
for (int i = 1; i < depth; i++)
{
str.append("+");
}
cout << str << m_name << endl;
}
void lineOfDuty()
{
cout << m_name << ":财务 " << endl;
}
};
int main()
{
std::cout << "Hello World!\n";
ConcreteCompany* root = new ConcreteCompany("北京总公司");
root->Add(new HRDepartment("总公司HR"));
root->Add(new FinanceDepartment("总公司CW"));
ConcreteCompany* comp = new ConcreteCompany("上海华东分公司");
comp->Add(new HRDepartment("上海华东分公司HR"));
comp->Add(new FinanceDepartment("上海华东分公司CW"));
root->Add(comp);
ConcreteCompany* comp1 = new ConcreteCompany("南京办事处");
comp1->Add(new HRDepartment("南京办事处HR"));
comp1->Add(new FinanceDepartment("南京办事处CW"));
comp->Add(comp1);
root->Display(1);
cout << "++++++++++++++++++++++++++++++" << endl;
root->lineOfDuty();
}
组合模式就这样定义了包含人力资源部和财务部这些基本对象和分公司,办事处等组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,而这些组合对象又可以被组合,这样不断地递归下去,在客户端代码中,任何用到基本对象的地方都可以使用组合对象了。
用户是不用关心到底处理一个叶节点还是处理一个组合组件,也就不用为定义组合而写一些选择判断语句了。即组合模式让客户可以一致的使用组合结构和单个对象。