结构型设计模式之组合模式【设计模式系列】

系列文章目录

C++技能系列
Linux通信架构系列
C++高性能优化编程系列
深入理解软件架构设计系列
高级C++并发线程编程
设计模式系列

期待你的关注哦!!!

现在的一切都是为将来的梦想编织翅膀,让梦想在现实中展翅高飞。
Now everything is for the future of dream weaving wings, let the dream fly in reality.

结构型设计模式之组合模式

一、组合模式介绍

⚠️ 意图:
将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

⚠️ 主要解决:
它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

⚠️ 何时使用:
1、您想表示对象的部分-整体层次结构(树形结构)。 2、您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

⚠️ 如何解决:
树枝和叶子实现统一接口,树枝内部组合该接口。

现有一个公司需要实现一个广播的功能,用来通知给公司所有部门重要的信息。如果需要广播,那么必须通过每一个部门类的实例去调用各自部门的广播接口。通过一个抽象类来抽象出广播接口,各个部门和公司都通过继承实现抽象接口。如此实现可以将所有部门放在一个容器内,遍历实现其广播接口。如果公司不扩大,永远有这几个部门并且没有分公司的话,是没问题的。如果再要添加一个部门,就必须实现一个部门类,再修改总公司类。这明显违背了开闭原则。既然我们通过抽象类来实现了其方法,那就可以实现抽象的增加,删除,查询接口。如此一来,如果要有新的部门, 那么只需要通过调用添加接口来增加新部门, 广播的时候,只需要遍历容器中的广播接口即可。实现类图如下:


图1_1 组合模式类图

组合模式,将对象组合成树形结构以表示"部分-整体"的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。掌握组合模式的重点是要理解清楚 "部分/整体" 还有 "单个对象" 与 "组合对象" 的含义。

组合模式可以让客户端像修改配置文件一样简单的完成本来需要流程控制语句来完成的功能。

二、组合模式优缺点

2.1 优点

  • 简化客户端调用,实现符合开闭原则。
  • 高层模块调用简单。
  • 节点自由增加

2.2 缺点

  • 如果业务逻辑负责,则实现组合模式比较困难。

  • 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。

三、组合模式使用场景

适用于"整体-部分"层次的树形结构的。部分、整体场景,如树形菜单,文件、文件夹的管理。

客户端对组合对象统一的使用所有对象。

四、组合模式实现

Component.h

cpp 复制代码
#ifndef COMPONENTS_H_
#define COMPONENTS_H_

#include <iostream>
#include <vector>

using namespace std;

class Components
{
public:
    Components(std::string strName):m_strName(strName){}

    virtual void Operation() = 0;
    virtual void AddSubCompany(Components* subCompany);
    virtual void DelSubCompany(Components* subCompany);
    virtual Components* GetCompanyByIndex(int iIndex);

protected:
    std::string m_strName;
};

class ConcreteCompany : public Components
{
public:
    ConcreteCompany(std::string strName):Components(strName){}
    ~ConcreteCompany();

    virtual void Operation();
    virtual void AddSubCompany(Components* subCompany);
    virtual void DelSubCompany(Components* subCompany);
    virtual Components* GetCompanyByIndex(int iIndex);
private:
    std::vector<Components*> m_vecSubItem;
};

class FinanceDepartment : public Components
{
public:
    FinanceDepartment(std::string strName):Components(strName){}

    virtual void Operation();
};

class HRDepartment : public Components
{
public:
    HRDepartment(std::string strName):Components(strName){}

    virtual void Operation();
};

#endif

Component.cpp

cpp 复制代码
#include "Company.h"
#include <algorithm>

#ifndef SAFE_DELETE
#define SAFE_DELETE(p){if((p) != NULL){delete (p); (p) = NULL;}}
#endif

void Components::AddSubCompany( Components* subCompany )
{
    cout << "Have no realized!" << endl;
}

void Components::DelSubCompany( Components* subCompany )
{
    cout << "Have no realized!" << endl;
}

Components* Components::GetCompanyByIndex( int iIndex )
{
    cout << "Have no realized!" << endl;
    return NULL;
}

//******************//
//**CentralCompany**//
//******************//

ConcreteCompany::~ConcreteCompany()
{
    std::for_each(m_vecSubItem.begin(),m_vecSubItem.end(),[&](Components* item)
    {
        SAFE_DELETE(item);
    });
}

void ConcreteCompany::Operation()
{
    std::for_each(m_vecSubItem.begin(),m_vecSubItem.end(),[&](Components* item)
    {
        item->Operation();
    });
}

void ConcreteCompany::AddSubCompany( Components* subCompany )
{
    if (subCompany != NULL)
    {
        m_vecSubItem.push_back(subCompany);
    }
}

void ConcreteCompany::DelSubCompany( Components* subCompany )
{
    for (auto it = m_vecSubItem.begin(); it != m_vecSubItem.end(); ++it)
    {
        if ((*it) == subCompany)
        {
            m_vecSubItem.erase(it);
            SAFE_DELETE(subCompany);
            break;
        }
    }
}

Components* ConcreteCompany::GetCompanyByIndex( int iIndex )
{
    if (iIndex < 0 || iIndex > m_vecSubItem.size())
    {
        return NULL;
    }
    return m_vecSubItem[iIndex];
}

void FinanceDepartment::Operation()
{
    cout << m_strName.c_str() << endl;
}

void HRDepartment::Operation()
{
    cout << m_strName.c_str() << endl;
}

main.cpp

cpp 复制代码
#include <iostream>
#include "Company.h"

using namespace std;

int main()
{
    Components* Central = new ConcreteCompany("Central Company");
    Central->AddSubCompany(new FinanceDepartment("Central Finance Department"));
    Central->AddSubCompany(new HRDepartment("Central HR Department"));

    Components* Xian = new ConcreteCompany("Xi'An Company");
    Xian->AddSubCompany(new FinanceDepartment("Xi'An Finance Department"));
    Xian->AddSubCompany(new HRDepartment("Xi'An HR Department"));

    Central->AddSubCompany(Xian);
    Central->Operation();

    cout << "<<<<<>>>>>" << endl;
    Central->DelSubCompany(Xian);
    Central->Operation();

    return 0;
}

输出:

bash 复制代码
Central Finance Department

Central HR Department

Xi'An Finance Department

Xi'An HR Department

<<<<<>>>>>

Central Finance Department

Central HR Department
相关推荐
数据智能老司机21 分钟前
CockroachDB权威指南——SQL调优
数据库·分布式·架构
数据智能老司机22 分钟前
CockroachDB权威指南——应用设计与实现
数据库·分布式·架构
XuanXu25 分钟前
Java AQS原理以及应用
java
数据智能老司机36 分钟前
CockroachDB权威指南——CockroachDB 模式设计
数据库·分布式·架构
风象南3 小时前
SpringBoot中6种自定义starter开发方法
java·spring boot·后端
mghio12 小时前
Dubbo 中的集群容错
java·微服务·dubbo
千千寰宇13 小时前
[设计模式/Java/多线程] 设计模式之单例模式【9】
设计模式·操作系统-进程/线程/并发
uhakadotcom14 小时前
视频直播与视频点播:基础知识与应用场景
后端·面试·架构
沉登c17 小时前
第 3 章 事务处理
架构