组合模式(Composite Pattern)及其应用场景

组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

模式定义

组合模式通过将对象组合成树状结构来表示部分-整体的层次结构,使得用户对单个对象和组合对象的使用具有一致性。

模式结构

  • Component(抽象构件): 定义叶子和容器构件的共同接口

  • Leaf(叶子构件): 表示叶节点对象,没有子节点

  • Composite(容器构件): 表示容器节点对象,存储子部件并实现与子部件相关的操作

  • Client(客户端): 通过Component接口操作组合结构中的对象

应用场景

  1. 需要表示对象的"部分-整体"层次结构时

  2. 希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时

  3. 处理树形结构数据时

  4. 当系统需要动态地在层次结构中添加新的构件时

优点

  1. 可以清楚地定义分层次的复杂对象

  2. 客户端可以一致地使用组合结构和单个对象

  3. 更容易在组合体内加入新的构件

  4. 简化了客户端代码,客户端可以一致地处理简单元素和复杂元素

缺点

  1. 设计较复杂,客户端需要花更多时间理清类之间的层次关系

  2. 很难限制组合中的构件类型

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

C++实用示例

示例1:文件系统实现

cpp 复制代码
#include <iostream>
#include <string>
#include <vector>
#include <memory>

// 抽象构件
class FileSystemComponent {
public:
    virtual ~FileSystemComponent() = default;
    virtual void display(int depth = 0) const = 0;
    virtual void add(std::unique_ptr<FileSystemComponent> component) {
        throw std::runtime_error("Cannot add to a leaf component");
    }
};

// 叶子构件 - 文件
class File : public FileSystemComponent {
    std::string name;
public:
    explicit File(const std::string& name) : name(name) {}
    void display(int depth = 0) const override {
        std::cout << std::string(depth * 2, ' ') << "- " << name << std::endl;
    }
};

// 容器构件 - 目录
class Directory : public FileSystemComponent {
    std::string name;
    std::vector<std::unique_ptr<FileSystemComponent>> children;
public:
    explicit Directory(const std::string& name) : name(name) {}
    
    void display(int depth = 0) const override {
        std::cout << std::string(depth * 2, ' ') << "+ " << name << std::endl;
        for (const auto& child : children) {
            child->display(depth + 1);
        }
    }
    
    void add(std::unique_ptr<FileSystemComponent> component) override {
        children.push_back(std::move(component));
    }
};

int main() {
    auto root = std::make_unique<Directory>("Root");
    
    auto documents = std::make_unique<Directory>("Documents");
    documents->add(std::make_unique<File>("Resume.pdf"));
    documents->add(std::make_unique<File>("CoverLetter.docx"));
    
    auto pictures = std::make_unique<Directory>("Pictures");
    pictures->add(std::make_unique<File>("Vacation.jpg"));
    pictures->add(std::make_unique<File>("Family.png"));
    
    auto downloads = std::make_unique<Directory>("Downloads");
    downloads->add(std::make_unique<File>("Setup.exe"));
    
    root->add(std::move(documents));
    root->add(std::move(pictures));
    root->add(std::make_unique<File>("README.txt"));
    root->add(std::move(downloads));
    
    root->display();
}

示例2:图形绘制系统

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <cmath>

// 抽象构件
class Graphic {
public:
    virtual ~Graphic() = default;
    virtual void move(int x, int y) = 0;
    virtual void draw() const = 0;
};

// 叶子构件 - 点
class Dot : public Graphic {
    int x, y;
public:
    Dot(int x, int y) : x(x), y(y) {}
    void move(int x, int y) override {
        this->x += x;
        this->y += y;
    }
    void draw() const override {
        std::cout << "Drawing a dot at (" << x << ", " << y << ")\n";
    }
};

// 叶子构件 - 圆
class Circle : public Graphic {
    int x, y;
    int radius;
public:
    Circle(int x, int y, int radius) : x(x), y(y), radius(radius) {}
    void move(int x, int y) override {
        this->x += x;
        this->y += y;
    }
    void draw() const override {
        std::cout << "Drawing a circle at (" << x << ", " << y 
                  << ") with radius " << radius << "\n";
    }
};

// 容器构件 - 组合图形
class CompoundGraphic : public Graphic {
    std::vector<std::unique_ptr<Graphic>> children;
public:
    void add(std::unique_ptr<Graphic> graphic) {
        children.push_back(std::move(graphic));
    }
    
    void move(int x, int y) override {
        for (const auto& child : children) {
            child->move(x, y);
        }
    }
    
    void draw() const override {
        std::cout << "=== Drawing a compound graphic ===\n";
        for (const auto& child : children) {
            child->draw();
        }
        std::cout << "=== End of compound graphic ===\n";
    }
};

int main() {
    auto all = std::make_unique<CompoundGraphic>();
    all->add(std::make_unique<Dot>(1, 2));
    all->add(std::make_unique<Circle>(5, 3, 10));
    
    auto group = std::make_unique<CompoundGraphic>();
    group->add(std::make_unique<Circle>(10, 10, 5));
    group->add(std::make_unique<Dot>(10, 10));
    
    all->add(std::move(group));
    all->add(std::make_unique<Dot>(20, 20));
    
    std::cout << "Initial drawing:\n";
    all->draw();
    
    all->move(5, 5);
    std::cout << "\nAfter moving (5,5):\n";
    all->draw();
}

示例3:组织架构系统

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 抽象构件
class OrganizationUnit {
public:
    virtual ~OrganizationUnit() = default;
    virtual void display(int depth = 0) const = 0;
    virtual void add(std::unique_ptr<OrganizationUnit> unit) {
        throw std::runtime_error("Cannot add to a leaf unit");
    }
    virtual double getSalary() const = 0;
};

// 叶子构件 - 员工
class Employee : public OrganizationUnit {
    std::string name;
    double salary;
public:
    Employee(const std::string& name, double salary) : name(name), salary(salary) {}
    void display(int depth = 0) const override {
        std::cout << std::string(depth * 2, ' ') << name 
                  << " (Salary: $" << salary << ")\n";
    }
    double getSalary() const override { return salary; }
};

// 容器构件 - 部门
class Department : public OrganizationUnit {
    std::string name;
    std::vector<std::unique_ptr<OrganizationUnit>> units;
public:
    explicit Department(const std::string& name) : name(name) {}
    
    void display(int depth = 0) const override {
        std::cout << std::string(depth * 2, ' ') << "Department: " << name 
                  << " (Total Salary: $" << getSalary() << ")\n";
        for (const auto& unit : units) {
            unit->display(depth + 1);
        }
    }
    
    void add(std::unique_ptr<OrganizationUnit> unit) override {
        units.push_back(std::move(unit));
    }
    
    double getSalary() const override {
        double total = 0.0;
        for (const auto& unit : units) {
            total += unit->getSalary();
        }
        return total;
    }
};

int main() {
    auto company = std::make_unique<Department>("ACME Corporation");
    
    auto engineering = std::make_unique<Department>("Engineering");
    engineering->add(std::make_unique<Employee>("John Doe", 85000));
    engineering->add(std::make_unique<Employee>("Jane Smith", 95000));
    
    auto qa = std::make_unique<Department>("Quality Assurance");
    qa->add(std::make_unique<Employee>("Bob Johnson", 75000));
    qa->add(std::make_unique<Employee>("Alice Williams", 80000));
    
    engineering->add(std::move(qa));
    company->add(std::move(engineering));
    
    auto marketing = std::make_unique<Department>("Marketing");
    marketing->add(std::make_unique<Employee>("Mike Brown", 90000));
    marketing->add(std::make_unique<Employee>("Sarah Davis", 88000));
    
    company->add(std::move(marketing));
    company->add(std::make_unique<Employee>("CEO", 250000));
    
    std::cout << "Company Structure:\n";
    company->display();
    
    std::cout << "\nTotal company salary: $" << company->getSalary() << std::endl;
}

示例4:UI组件系统

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 抽象构件
class UIComponent {
public:
    virtual ~UIComponent() = default;
    virtual void render() const = 0;
    virtual void add(std::unique_ptr<UIComponent> component) {
        throw std::runtime_error("Cannot add to a leaf component");
    }
};

// 叶子构件 - 按钮
class Button : public UIComponent {
    std::string label;
public:
    explicit Button(const std::string& label) : label(label) {}
    void render() const override {
        std::cout << "[Button: " << label << "]\n";
    }
};

// 叶子构件 - 文本框
class TextBox : public UIComponent {
    std::string placeholder;
public:
    explicit TextBox(const std::string& placeholder) : placeholder(placeholder) {}
    void render() const override {
        std::cout << "[TextBox: " << placeholder << "]\n";
    }
};

// 容器构件 - 面板
class Panel : public UIComponent {
    std::string title;
    std::vector<std::unique_ptr<UIComponent>> children;
public:
    explicit Panel(const std::string& title) : title(title) {}
    
    void render() const override {
        std::cout << "=== Panel: " << title << " ===\n";
        for (const auto& child : children) {
            child->render();
        }
        std::cout << "=== End of Panel ===\n";
    }
    
    void add(std::unique_ptr<UIComponent> component) override {
        children.push_back(std::move(component));
    }
};

// 容器构件 - 窗口
class Window : public UIComponent {
    std::string title;
    std::vector<std::unique_ptr<UIComponent>> children;
public:
    explicit Window(const std::string& title) : title(title) {}
    
    void render() const override {
        std::cout << "**** Window: " << title << " ****\n";
        for (const auto& child : children) {
            child->render();
        }
        std::cout << "**** End of Window ****\n";
    }
    
    void add(std::unique_ptr<UIComponent> component) override {
        children.push_back(std::move(component));
    }
};

int main() {
    auto loginWindow = std::make_unique<Window>("Login");
    
    auto formPanel = std::make_unique<Panel>("Login Form");
    formPanel->add(std::make_unique<TextBox>("Username"));
    formPanel->add(std::make_unique<TextBox>("Password"));
    
    auto buttonPanel = std::make_unique<Panel>("Actions");
    buttonPanel->add(std::make_unique<Button>("Login"));
    buttonPanel->add(std::make_unique<Button>("Cancel"));
    
    loginWindow->add(std::move(formPanel));
    loginWindow->add(std::move(buttonPanel));
    
    std::cout << "Rendering UI:\n";
    loginWindow->render();
}

这些示例展示了组合模式如何通过树形结构来表示部分-整体层次结构,使得客户端可以一致地处理单个对象和组合对象。组合模式特别适合用于构建递归结构,如文件系统、UI组件、组织结构等场景。