组合模式:

定义:

  组合模式又叫部分整体模式,它是一种将对象组合成树状的层次结构模式,用来表示"部分-整体"的关系,使用户对单个对象和组合对象具有一致的访问性。

组合模式的角色:

  1. 抽象构建(Component):它的主要作用是为树叶构件和树枝构件声明公共接口,并实现它们的默认行为。在透明式的组合模式中抽象构件还声明访问和管理子类的接口;在安全式的组合模式中不声明访问和管理子类的接口,管理工作由树枝构件完成。
  2. 树叶构件(Leaf):是组合中的叶节点对象,它没有子节点,用于实现抽象构件角色中 声明的公共接口。
  3. 树枝构件(Composite):是组合中的分支节点对象,它有子节点。它实现了抽象构件角色中声明的接口,它的主要作用是存储和管理子部件,通常包含 Add()、Remove()、GetChild() 等方法。

优点:

  1. 组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的单个对象还是组合对象,这简化了客户端代码;
  2. 更容易在组合体内加入新的对象,客户端不会因为加入新的对象而更改源代码,满足OCP原则。

缺点:

  1. 设计较复杂,客户端需要花更多的时间理清类之间的层次关系;
  2. 不容易限制容器中的构件;
  3. 不容易用继承的方法来增加构件的新功能。

eg:

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();
		}
	}
};

//-----------------------------------------------
//use
	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();