《C++新经典设计模式》之第11章 组合模式

        • 组合模式.cpp

组合模式.cpp
#include #include #include #include #include #include using namespace std;// 主要用来处理树形结构的数据// 将一组对象(文件和目录)组织成树形结构以表示“部分-整体”的层次结构(目录中包含文件和子目录)// 使得用户对单个对象(文件)和组合对象(目录)的操作/使用/处理(递归遍历并执行ShowName等)具有一致性// 3种角色// Component(抽象组件),为树枝和树叶定义接口(增加,删除,获取子节点等)// Leaf(叶子组件),表示树叶节点对象,没有子节点// Composite(树枝组件),表示容器(树枝)节点对象,可以包含子节点树枝或树叶// 透明组合模式// 所有组件都有相同接口,即使叶节点中无意义(Add,Remove)// 安全组合模式// 不够透明,管理和访问子节点的成员函数(接口)不在抽象组件中定义namespace ns1{class File // 文件相关类{string m_sname; // 文件名public:File(const string &name) : m_sname(name) {}void ShowName(const string &lvlstr) const // 显示文件名{cout << lvlstr << "-" << m_sname << endl; // 显示"-"代表是一个文件,属末端节点(不会再有子节点)}};class Dir // 目录相关类{string m_sname; // 目录名list<shared_ptr<File>> m_childFile; // 文件列表list<shared_ptr<Dir>> m_childDir; // 子目录列表public:Dir(const string &name) : m_sname(name) {}public:void AddFile(const shared_ptr<File> &pfile) { m_childFile.push_back(pfile); }void AddDir(const shared_ptr<Dir> &pdir) { m_childDir.push_back(pdir); }// 显示目录名,同时也要负责其下面的文件和目录名的显示工作void ShowName(const string &lvlstr) const // lvlstr:为了显示层次关系的缩进字符串内容{// (1)输出本目录名cout << lvlstr << "+" << m_sname << endl; // 显示"+"代表是一个目录,其中会包含其他内容// (2)输出所包含的文件名for (auto iter = m_childFile.cbegin(); iter != m_childFile.cend(); ++iter)(*iter)->ShowName(lvlstr + ""); // 显示文件名// (3)输出所包含的目录名for (auto iter = m_childDir.cbegin(); iter != m_childDir.cend(); ++iter)(*iter)->ShowName(lvlstr + ""); // 显示目录名,这里涉及到了递归调用}};}namespace ns2{class FileSystem // 抽象接口{public:virtual ~FileSystem() {}virtual void ShowName(int level) const = 0; // 显示名字,参数level用于表示显示的层级,用于显示对齐virtual int Add(const shared_ptr<FileSystem> &pfilesys) = 0;// 向当前目录中增加文件或子目录virtual int Remove(const shared_ptr<FileSystem> &pfilesys) = 0; // 从当前目录中移除文件或子目录};class File : public FileSystem // 文件相关类{string m_sname; // 文件名public:File(const string &name) : m_sname(name) {}void ShowName(int level) const{for (int i = 0; i < level; ++i) // 显示若干个空格用与对齐cout << "";cout << "-" << m_sname << endl;}int Add(const shared_ptr<FileSystem> &pfilesys) override { return -1; }int Remove(const shared_ptr<FileSystem> &pfilesys) override { return -1; }};class Dir : public FileSystem // 目录相关类{string m_sname; // 文件名list<shared_ptr<FileSystem>> m_child; // 目录中包含的文件或其他目录列表public:Dir(const string &name) : m_sname(name) {}void ShowName(int level) const{// (1)显示若干个空格用与对齐for (int i = 0; i < level; ++i)cout << "";// (2)输出本目录名cout << "+" << m_sname << endl;// (3)输出所包含的子内容(可能是文件,也可能是子目录)for (auto iter = m_child.cbegin(); iter != m_child.cend(); ++iter)(*iter)->ShowName(level + 1);}int Add(const shared_ptr<FileSystem> &pfilesys) override{m_child.push_back(pfilesys);return 0;}int Remove(const shared_ptr<FileSystem> &pfilesys) override{m_child.remove(pfilesys);return 0;}};}namespace ns3{class Dir;class FileSystem // 抽象接口{public:virtual void ShowName(int level) const = 0; // 显示名字,参数level用于表示显示的层级,用于显示对齐virtual ~FileSystem() {}public:virtual Dir *ifCompositeObj() { return nullptr; }virtual int countNumOfFiles() const = 0; // 统计目录下包含的文件个数};class File : public FileSystem // 文件相关类{string m_sname; // 文件名public:File(const string &name) : m_sname(name) {}void ShowName(int level) const override{for (int i = 0; i < level; ++i)cout << "";cout << "-" << m_sname << endl;}public:int countNumOfFiles() const override { return 1; }};class Dir : public FileSystem{string m_sname; // 文件名list<shared_ptr<FileSystem>> m_child; // 目录中包含的文件或其他目录列表public:Dir(const string &name) : m_sname(name) {}void ShowName(int level) const override{// (1)显示若干个空格用与对齐for (int i = 0; i < level; ++i)cout << "";// (2)输出本目录名cout << "+" << m_sname << endl;// (3)输出所包含的子内容(可能是文件,也可能是子目录)for (auto iter = m_child.cbegin(); iter != m_child.cend(); ++iter)(*iter)->ShowName(level + 1);}int Add(const shared_ptr<FileSystem> &pfilesys){m_child.push_back(pfilesys);return 0;}int Remove(const shared_ptr<FileSystem> &pfilesys){m_child.remove(pfilesys);return 0;}public:Dir *ifCompositeObj() override { return this; }public:int countNumOfFiles() const override{int iNumOfFiles = 0;for (auto iter = m_child.cbegin(); iter != m_child.cend(); ++iter)iNumOfFiles += (*iter)->countNumOfFiles(); // 递归调用return iNumOfFiles;}};}namespace ns4{class Employee{string name;string dept;int salary;vector<shared_ptr<Employee>> subordinates;public:Employee(const string &m_name, const string &m_dept, int m_salary) : name(m_name), dept(m_dept), salary(m_salary) {}void add(const shared_ptr<Employee> &e) { subordinates.push_back(e); }void remove(const shared_ptr<Employee> &e){auto it = find(subordinates.cbegin(), subordinates.cend(), e);if (it != subordinates.cend())subordinates.erase(it);}const vector<shared_ptr<Employee>> &getSubordinates() const { return subordinates; }string toString(){return ("Employee :[ Name : " + name + ", dept : " + dept + ", salary :" + to_string(salary) + " ]");}};}int main(){#if 0using namespace ns1;// (1)创建各种目录,文件对象shared_ptr<Dir> pdir1(new Dir("root"));//-------shared_ptr<File> pfile1(new File("common.mk"));shared_ptr<File> pfile2(new File("config.mk"));shared_ptr<File> pfile3(new File("makefile"));//-------shared_ptr<Dir> pdir2(new Dir("app"));shared_ptr<File> pfile4(new File("nginx.c"));shared_ptr<File> pfile5(new File("ngx_conf.c"));//-------shared_ptr<Dir> pdir3(new Dir("signal"));shared_ptr<File> pfile6(new File("ngx_signal.c"));//-------shared_ptr<Dir> pdir4(new Dir("_include"));shared_ptr<File> pfile7(new File("ngx_func.h"));shared_ptr<File> pfile8(new File("ngx_signal.h"));// (2)构造树形目录结构pdir1->AddFile(pfile1);pdir1->AddFile(pfile2);pdir1->AddFile(pfile3);//-------pdir1->AddDir(pdir2);pdir2->AddFile(pfile4);pdir2->AddFile(pfile5);//-------pdir1->AddDir(pdir3);pdir3->AddFile(pfile6);//-------pdir1->AddDir(pdir4);pdir4->AddFile(pfile7);pdir4->AddFile(pfile8);// (3)输出整个目录结构,只要调用根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录的显示pdir1->ShowName(""); // 缩进字符刚开始可以为空#endif#if 0using namespace ns2;// (1)创建各种目录,文件对象shared_ptr<FileSystem> pdir1(new Dir("root"));//-------shared_ptr<FileSystem> pfile1(new File("common.mk"));shared_ptr<FileSystem> pfile2(new File("config.mk"));shared_ptr<FileSystem> pfile3(new File("makefile"));//-------shared_ptr<FileSystem> pdir2(new Dir("app"));shared_ptr<FileSystem> pfile4(new File("nginx.c"));shared_ptr<FileSystem> pfile5(new File("ngx_conf.c"));//-------shared_ptr<FileSystem> pdir3(new Dir("signal"));shared_ptr<FileSystem> pfile6(new File("ngx_signal.c"));//-------shared_ptr<FileSystem> pdir4(new Dir("_include"));shared_ptr<FileSystem> pfile7(new File("ngx_func.h"));shared_ptr<FileSystem> pfile8(new File("ngx_signal.h"));// (2)构造树形目录结构pdir1->Add(pfile1);pdir1->Add(pfile2);pdir1->Add(pfile3);//-------pdir1->Add(pdir2);pdir2->Add(pfile4);pdir2->Add(pfile5);//-------pdir1->Add(pdir3);pdir3->Add(pfile6);//-------pdir1->Add(pdir4);pdir4->Add(pfile7);pdir4->Add(pfile8);// (3)输出整个目录结构,只要调用根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录的显示pdir1->ShowName(0);#endif#if 0using namespace ns3;// (1)创建各种目录,文件对象shared_ptr<Dir> pdir1(new Dir("root"));//-------shared_ptr<FileSystem> pfile1(new File("common.mk"));shared_ptr<FileSystem> pfile2(new File("config.mk"));shared_ptr<FileSystem> pfile3(new File("makefile"));//-------shared_ptr<Dir> pdir2(new Dir("app"));if (pdir2->ifCompositeObj() != nullptr){// 是个组合对象,可以向其中增加单个对象和其它组合对象}if (dynamic_pointer_cast<Dir>(pdir2) != nullptr){// 是个组合对象,可以向其中增加单个对象和其它组合对象}shared_ptr<FileSystem> pfile4(new File("nginx.c"));shared_ptr<FileSystem> pfile5(new File("ngx_conf.c"));//-------shared_ptr<Dir> pdir3(new Dir("signal"));shared_ptr<FileSystem> pfile6(new File("ngx_signal.c"));//-------shared_ptr<Dir> pdir4(new Dir("_include"));shared_ptr<FileSystem> pfile7(new File("ngx_func.h"));shared_ptr<FileSystem> pfile8(new File("ngx_signal.h"));// (2)构造树形目录结构pdir1->Add(pfile1);pdir1->Add(pfile2);pdir1->Add(pfile3);//-------pdir1->Add(pdir2);pdir2->Add(pfile4);pdir2->Add(pfile5);//-------pdir1->Add(pdir3);pdir3->Add(pfile6);//-------pdir1->Add(pdir4);pdir4->Add(pfile7);pdir4->Add(pfile8);// (3)输出整个目录结构,只要调用根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录的显示pdir1->ShowName(0);cout << "number of files: " << pdir1->countNumOfFiles() << endl;#endif#if 1using namespace ns4;shared_ptr<Employee> clerk1(new Employee("Laura", "Marketing", 10000));shared_ptr<Employee> clerk2(new Employee("Bob", "Marketing", 10000));shared_ptr<Employee> headMarketing(new Employee("Michel", "Head Marketing", 20000));headMarketing->add(clerk1);headMarketing->add(clerk2);shared_ptr<Employee> salesExecutive1(new Employee("Richard", "Sales", 10000));shared_ptr<Employee> salesExecutive2(new Employee("Rob", "Sales", 10000));shared_ptr<Employee> headSales(new Employee("Robert", "Head Sales", 20000));headSales->add(salesExecutive1);headSales->add(salesExecutive2);shared_ptr<Employee> CEO(new Employee("John", "CEO", 30000));CEO->add(headSales);CEO->add(headMarketing);cout << CEO->toString() << endl;cout << "------------------------------------------------------------" << endl;for (const shared_ptr<Employee> &e : CEO->getSubordinates()){cout << e->toString() << endl;for (const shared_ptr<Employee> &ee : e->getSubordinates())cout << ee->toString() << endl;}#endifcout << "Over!\n";return 0;}