组合模式
理论
组合模式(Composite),将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
透明方式与安全方式
透明方式:在 Leaf 类当中也有 Add 和 Remove 方法。这种方式叫做透明方式,在 Compoment 中声明所有用来管理子对象的方法,其中包括 Add、Remove 等。这样实现 Component 接口的所有子类都具备了 Add 和 Remove。这样做的好处就是叶节点和枝结点对于外界没有区别,它们具备完全一致的行为接口。但问题也很明显,因为 Leaf 类本身不具备 Add()、Remove() 方法的功能,所以实现它是没有意义的。
安全方式:在 Leaf 类当中不用 Add 和 Remove方法。在 Component 接口中不去声明 Add 和 Remove 方法,那么子类的 Leaf 就不需要去实现它,而是在 Composite 声明所有用来管理子类对象的方法,这样就不会出现透明方式中的问题。不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端的调用需要做相应的判断,带来了不变。
组合模式的应用场景
1. 当需求中是体现部分与整体层次的结构时
2. 希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中地所有对象时
组合模式的优点
组合模式定义包含了基本对象和组合对象的类层次结构。基本对象可以被组合成更复杂的组合对象,组合对象又可以被组合,这样不断地递归下去,客户代码中,任何用到基本对象的地方都可以使用组合对象。
因此用户不用关心到底是处理一个叶节点还是处理一个组合组件,也就不需要为定义组合而写一些选择判断语句。
组合模式让客户可以一致地使用组合结构和单个对象。
实例
模拟公司管理系统如下图
特征:整体与部分可以被一致对待
UML类图
代码实现
#include <iostream> #include <list> using namespace std; //公司类 (抽象类) class Company { public: Company(string _name) :name(_name) {} virtual void Add(Company* c) = 0; //增加 virtual void Remove(Company* c) = 0; //移除 virtual void Display(int depth) = 0; //显示 virtual void LineOfDuty() = 0; //旅行职责 protected: string name; }; //其他公司类 实现接口 树枝结点 class ConcreteCompany : public Company{ public: ConcreteCompany(string _name) :Company(_name) {} virtual void Add(Company* c){ children.push_back(c); } void Remove(Company* c) { children.remove(c); } virtual void Display(int depth) { string s(depth, '-'); cout << s << name << endl; for (list<Company*>::iterator it = children.begin(); it != children.end(); it++) { (*it)->Display(depth + 2); } } virtual void LineOfDuty() { for (list<Company*>::iterator it = children.begin(); it != children.end(); it++) { (*it)->LineOfDuty(); } } private: list<Company*> children; }; //人力资源部与财务部类 树叶结点 class HRDepartment : public Company { public: HRDepartment(string _name) :Company(_name) {} virtual void Add(Company* c) {} virtual void Remove(Company* c) {} virtual void Display(int depth) { string s(depth, '-'); cout << s << name << endl; } virtual void LineOfDuty() { cout << name << " 员工招聘培训管理" << endl; } }; //财务部 class FinanceDepartment : public Company { public: FinanceDepartment(string _name) :Company(_name) {} virtual void Add(Company* c) {} virtual void Remove(Company* c) {} virtual void Display(int depth) { string s(depth, '-'); cout << s << name << endl; } virtual void LineOfDuty() { cout << name << " 公司财务收支管理" << endl; } }; //客户端调用 int main() { ConcreteCompany* root = new ConcreteCompany("北京总公司"); root->Add(new HRDepartment("总公司人力资源部")); root->Add(new FinanceDepartment("总公司财务部")); ConcreteCompany* comp = new ConcreteCompany("上海华东分公司"); comp->Add(new HRDepartment("华东分公司人力资源部")); comp->Add(new FinanceDepartment("华东分公司财务部")); root->Add(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); cout << "结构图:" << endl; root->Display(1); cout << endl; cout << "职责:" << endl; root->LineOfDuty(); delete root; delete comp; delete comp1; delete comp2; system("pause"); return 0; }