Bootstrap

设计模式之组合模式

在现代软件开发中,设计模式是一种解决特定问题的通用方法。组合模式(Composite Pattern)是一种重要的结构型设计模式,用于描述如何构建树状对象结构,使得单个对象和对象组合可以被统一对待。

本文将详细介绍组合模式的定义、应用场景、实现原理,并结合一段基于 C++ 的公司组织结构管理代码,深入剖析其设计与实现。


一、组合模式简介

1.1 定义

组合模式通过将对象组合成树状结构来表示“整体/部分”层次结构,使得客户端能够以一致的方式处理单个对象和对象的组合。

在组合模式中,“组合对象”包含一个或多个子对象,它可以在需要时递归调用这些子对象的操作。


1.2 主要角色

组合模式包含以下关键角色:

  • 组件(Component): 定义组合对象和叶子对象的统一接口。
  • 叶子节点(Leaf): 表示树的叶子节点,不能包含子节点,实现组件接口。
  • 组合节点(Composite): 包含子节点并定义管理子节点的方法,如addremove

1.3 适用场景

组合模式适用于以下场景:

  1. 树形结构数据: 例如企业组织结构、文件系统、GUI组件等。
  2. 一致性操作: 希望以相同方式处理单个对象和对象组合。
  3. 递归调用: 需要对子对象执行操作时,递归地处理每个子对象。

二、C++实现公司组织结构管理系统

为了展示组合模式的应用,我们通过一个模拟的企业组织结构管理系统来演示。

2.1 系统需求

公司组织结构由多个层级组成:

  • 总公司包含多个部门。
  • 每个部门承担不同的职责。
  • 总公司还可以包含分公司,分公司可以有自己的部门。

系统需支持以下功能:

  1. 添加或移除子节点(子公司、部门)。
  2. 显示组织结构的层级关系。
  3. 执行各部门的具体工作。

2.2 类设计

我们使用组合模式来设计以下类:

  1. Company(抽象基类):统一定义所有公司及部门的接口。
  2. DetCompany(组合类):表示公司,允许包含多个子节点。
  3. HDDepartment(叶子类):人事部门,负责人员管理。
  4. MODepartment(叶子类):财务部门,负责财务管理。
抽象基类 Company

Company 是所有类的基类,定义了公司和部门的公共接口。其定义如下:

class Company
{
protected:
    string name; // 公司或部门名称
public:
    Company(string name):name(name){} // 构造函数
    virtual void add(Company* c) = 0;    // 添加子节点
    virtual void remove(Company* c) = 0; // 移除子节点
    virtual void show(int depth) = 0;    // 显示结构
    virtual void work() = 0;             // 执行工作

    // 重载 == 运算符,用于比较公司或部门名称
    bool operator==(const Company&c) const
    {
        return this->name == c.name;
    }
};


组合类 DetCompany

DetCompany 继承自 Company,表示一个可以包含子节点的公司或分公司。其实现如下:

class DetCompany:public Company
{
    list <Company*> *children; // 子节点列表
public:
    DetCompany(string name):Company(name)
    {
        children = new list<Company*>;
    }
    ~DetCompany()
    {
        for(list<Company*>::iterator it = children->begin(); it != children->end(); it++)
        {
            delete *it; // 递归删除所有子节点
        }
        delete children;
    }

    void add(Company* c)
    {
        children->push_back(c); // 添加子节点
    }

    void remove(Company* c)
    {
        for(list<Company*>::iterator it = children->begin(); it != children->end(); it++)
        {
            if (**it == *c) // 找到匹配的子节点
            {
                delete *it; // 删除子节点
                it = children->erase(it);
            }
        }
    }

    void show(int depth)
    {
        for (int i = 0; i < depth; i++) cout << "-"; // 显示层级结构
        cout << name << endl;
        for (list<Company*>::iterator it = children->begin(); it != children->end(); it++)
        {
            (*it)->show(depth + 2); // 递归显示子节点
        }
    }

    void work()
    {
        for (list<Company*>::iterator it = children->begin(); it != children->end(); it++)
        {
            (*it)->work(); // 递归调用子节点的工作
        }
    }
};

叶子类 HDDepartmentMODepartment

这些类表示没有子节点的部门,直接实现工作逻辑:

class HDDepartment:public Company
{
public:
    HDDepartment(string name):Company(name){}
    void add(Company* c){}       // 不支持添加子节点
    void remove(Company* c){}    // 不支持移除子节点
    void show(int depth)
    {
        for (int i = 0; i < depth; i++) cout << "-";
        cout << name << endl;
    }

    void work()
    {
        cout << name << " 负责招聘和人员管理" << endl;
    }
};

class MODepartment:public Company
{
public:
    MODepartment(string name):Company(name){}
    void add(Company* c){}       // 不支持添加子节点
    void remove(Company* c){}    // 不支持移除子节点
    void show(int depth)
    {
        for (int i = 0; i < depth; i++) cout << "-";
        cout << name << endl;
    }

    void work()
    {
        cout << name << " 负责公司财务管理" << endl;
    }
};

2.3 主函数实现

以下是测试代码:

int main()
{
    // 创建总公司
    Company* root = new DetCompany("北大青鸟北京总公司");
    root->add(new HDDepartment("总公司人事部"));
    root->add(new MODepartment("总公司财务部"));

    // 创建分公司
    Company* son = new DetCompany("合肥课工场");
    son->add(new HDDepartment("课工场人事部"));
    son->add(new MODepartment("课工场财务部"));

    root->add(son); // 添加分公司到总公司

    cout << "组织结构:" << endl;
    root->show(1); // 显示结构

    root->remove(son); // 移除分公司

    cout << "\n移除分公司后的组织结构:" << endl;
    root->show(1); // 显示新的结构

    cout << "\n各部门工作情况:" << endl;
    root->work(); // 显示各部门工作
}

2.4 运行结果

组织结构:
-北大青鸟北京总公司
--总公司人事部
--总公司财务部
--合肥课工场
----课工场人事部
----课工场财务部

移除分公司后的组织结构:
-北大青鸟北京总公司
--总公司人事部
--总公司财务部

各部门工作情况:
总公司人事部 负责招聘和人员管理
总公司财务部 负责公司财务管理

三、组合模式的优缺点

3.1 优点

  1. 清晰的层次结构: 可以直观地表示“整体-部分”关系。
  2. 统一操作接口: 客户端不需要区分单个对象和组合对象。
  3. 灵活扩展性: 动态添加或移除子节点。

3.2 缺点

  1. 复杂性增加: 对于简单结构可能显得过于复杂。
  2. 节点间关系难以限制: 客户端可能无意中破坏树结构。

四、总结

组合模式为我们提供了一种优雅的方式来表示层次结构和递归操作。通过本文的代码示例,我们展示了如何利用组合模式设计公司组织结构管理系统,从而实现灵活的管理与扩展。

如果你正面临类似的设计问题,不妨尝试将组合模式应用到你的系统中!

;