结构型模式之组合模式

一、概述

1、定义:组合多个对象形成树形结构以表示具有部分-整体关系的层次结构

2、组合模式让客户端统一对待单个对象和组合对象

3、组合模式又称为部分-整体模式

4、将对象组织到树形结构中,可以用来描述整体与部分的关系

二、组合模式的结构

组合模式包含以下3个角色:

1、Component(抽象构件):是组合模式中最重要的接口或抽象类,它声明了访问及管理子组件的方法,如增加、删除、获取子组件等

2、Leaf(叶子构件):是组合模式中的基本对象,它实现了抽象组件中定义的行为,并且没有子组件

3、Composite(容器对象):这是包含子组件的组合对象,它可以包含叶子组件和其它容器组件,形成一个树形结构。

三、UML图

结构型模式之组合模式_第1张图片

四、组合模式实现步骤

1、定义接口(component)

//定义接口(Component)
class Component
{
public:
	virtual ~Component() = default;
	virtual void add(std::shared_ptr component) = 0;
	virtual void remove(Component* component) = 0;
	virtual Component* getChild(int index) = 0;
	virtual int getChildIndex() const = 0;
	virtual bool isComposite() const = 0;
	virtual bool isLeaf() const = 0;
	virtual void operatoin() const = 0;
};

2、实现叶子组件(Leaf)

创建一个或多个叶子组件类,继承实现抽象组件接口。在叶子组件类中,实现了抽象组件接口中定义的方法,但叶子组件不会再有子组件,所以添加和删除子组件方法执行空操作

//实现叶子组件(Leaf)类
class Leaf : public Component
{
public:
	Leaf(const string &name) : m_name(name){}

	void add(std::shared_ptr component) override
	{
		cout << "Leaf unable add children" << endl;
	}

	void remove(Component* component) override
	{
		cout << "Leaf unable remove children" << endl;
	}

	Component* getChild(int index) override
	{
		return nullptr;
	}

	int getChildIndex() const override
	{
		return 0;
	}

	bool isComposite() const override
	{
		return false;
	}

	bool isLeaf() const override
	{
		return true;
	}

	void operatoin() const override
	{
		cout << "Leaf operation" << endl;
	}

private:
	string m_name;
};

3、实现容器组件(Composite)

创建一个容器组件类,继承实现抽象组件接口。在容器组件类中,除了实现抽象组件接口中定义的方法外,还需要维护一个子组件列表,提供方法来添加、删除和获取子组件。

//实现容器组件类(Composite)类
class Composite : public Component
{
public:
	Composite(const string &name) : m_name(name) {}

	void add(std::shared_ptr component) override
	{
		m_children.push_back(std::move(component));
	}

	void remove(Component* component) override
	{
		auto it = std::find_if(m_children.begin(), m_children.end(), [component](const std::shared_ptr& t) {
			return t.get() == component;
			});

		if (it != m_children.end())
			m_children.erase(it);
		else
			cout << "Composite not found children" << endl;
	}

	Component* getChild(int index) override
	{
		if (index < 0 || index >= m_children.size())
			return nullptr;

		return m_children[index].get();
	}

	int getChildNum() const override
	{
		return m_children.size();
	}

	bool isComposite() const override
	{
		return true;
	}

	bool isLeaf() const override
	{
		return false;
	}

	void operatoin() const override
	{
		cout << "Composite operation" << endl;
		for (int i = 0; i < m_children.size(); ++i)
			m_children.at(i)->operatoin();
	}
private:
	string m_name;
	vector> m_children;
};

4、组合组件

在客户端,可以创建叶子组件和容器组件实例,并将它们组合成树形结构

int main()
{
	std::shared_ptr leafA = std::make_shared("leafA");
	std::shared_ptr leafB = std::make_shared("leafB");

	std::shared_ptr composite = std::make_shared("composite");

	composite->add(std::move(leafA));
	composite->add(std::move(leafB));

	composite->operatoin();
}

这个示例中展示了组合模式的基本结构和使用方式,可以根据需要进行扩展,添加更多的组件类型、方法或操作

五、组合模式的应用场景

1、图形绘制:在图形系统中,图形对象可以是单独的形状(如圆形、矩形)或由多个形状组合成的复杂图形。使用组合模式可以统一处理单个形状和由形状组成的图形组合

2、文件系统:文件系统中的文件和文件夹可以形成树形结构。文件夹可以包含其他文件夹或文件,使用组合模式可以一致地处理文件和文件夹的操作。

3、用户界面(GUI):用户界面组件(如按钮、面板、菜单)可以组成复杂的界面层次结构。组合模式可以帮助统一处理这些组件的操作和显示。

4、树形数据结构:在处理树形数据结构时,例如XML文档、目录结构或组织图,组合模式可以帮助简化对这些结构的操作。

5、组织架构:在公司或其他组织中,员工可以有不同的层级和角色。员工(单个节点)和部门(包含多个员工和部门的组合)可以使用组合模式来表示和处理。

六、组合模式应用于图形界面(GUI)

#include 
#include 
#include 

// 组件接口
class Component {
public:
    virtual ~Component() = default;
    virtual void render() const = 0;
};

// 叶子节点
class Button : public Component {
public:
    Button(const std::string& name) : name(name) {}

    void render() const override {
        std::cout << "Rendering button: " << name << std::endl;
    }

private:
    std::string name;
};

// 组合节点
class Panel : public Component {
public:
    ~Panel() override = default;

    void add(std::shared_ptr component) {
        children.push_back(component);
    }

    void remove(std::shared_ptr component) {
        auto it = std::remove(children.begin(), children.end(), component);
        children.erase(it, children.end());
    }

    void render() const override {
        std::cout << "Rendering panel" << std::endl;
        for (const auto& child : children) {
            child->render();
        }
    }

private:
    std::vector> children;
};

// 客户端代码
int main() 
{
      // 创建按钮和面板
    auto button1 = std::make_shared

七、模式优点

1、可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,让客户端忽略了层次的差异,方便对整个层次结构进行控制

2、增加新的容器构件和叶子构件都很方便,符合开闭原则

3、为树形结构的面向对象实现提供了一种灵活的解决方案

八、模式缺点

1、在增加新构件时,很难对容器中的构件类型进行限制

你可能感兴趣的:(设计模式,组合模式)