组合模式,将对象组合成属性结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。其UML图如下:
一个组织有很多子组织,而无论子组织是单独一个部门或是一个分组织。该组织都希望把它们当成一样的子组织来管理。举个例子吧,就拿公司来说吧,一个公司总部为了方便管理希望把分公司当成一个部门来管理就行了。比如公司要发奖金了,总公司只用通知自己的所有部门就可以了。对于分公司,只用通知分公司就可以了,而不用一一通知分公司的各个部门。具体的实现就是Composite中有一个自己子组织的列表,当有什么通知要执行时,按顺序通知列表中的子组织就行了。而如果子组织中有组织的话也时执行相同的操作,因为它们都实现了相同的接口。
示例代码如下:
// CompositeModel.h文件 #pragma once #include <iostream> #include <string> #include <vector> #include <algorithm> class ComponentPtr { protected: std::string m_strName; public: ComponentPtr(std::string str) { m_strName = str; } virtual void add(ComponentPtr * p) = 0; virtual void remove(ComponentPtr * p) = 0; virtual void display() = 0; }; class LeafPtr : public ComponentPtr { public: LeafPtr(std::string str) : ComponentPtr(str) {} void add(ComponentPtr * p) { std::cout << "Leaf cannot add" << std::endl; } void remove(ComponentPtr * p) { std::cout << "Leaf cannot remove" << std::endl; } void display() { std::cout << m_strName << std::endl; } }; class CompositePtr : public ComponentPtr { private: // 这里使用智能指针不用自己释放new的内存 std::vector<std::shared_ptr<ComponentPtr>> m_vec; public: CompositePtr(std::string str) : ComponentPtr(str) {}; ~CompositePtr() { if (!m_vec.empty()) { m_vec.clear(); } } void add(ComponentPtr * p) { auto it = find_if(m_vec.begin(), m_vec.end(), [p](std::shared_ptr<ComponentPtr> ptr) {return p == ptr.get(); }); if (it == m_vec.end()) m_vec.push_back(std::shared_ptr<ComponentPtr>(p)); } void remove(ComponentPtr * p) { auto it = find_if(m_vec.begin(), m_vec.end(), [p](std::shared_ptr<ComponentPtr> ptr) {return p == ptr.get(); }); if (it == m_vec.end()) return; m_vec.erase(it); } void display() { for (auto it = m_vec.cbegin(); it != m_vec.cend(); it++) { (*it)->display(); } } };测试代码如下:
#include <iostream> #include "CompositeModel.h" int main() { using namespace std; // 组合模式 CompositePtr * p = new CompositePtr("总部"); p->add(new LeafPtr("总部财务部门")); p->add(new LeafPtr("总部人力资源部门")); CompositePtr * p1 = new CompositePtr("上海分部"); p1->add(new LeafPtr("上海分部财务部门")); p1->add(new LeafPtr("上海分部人力资源部门")); p->add(p1); p->display(); getchar() return 0; }测试结果如下图: 当你发现需求中是体现部分于整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,同意使用组合结构中的所有对象时,就应该考虑使用组合模式了。