楼主: 张凯max
142 0

[問題求助] C++设计模式之组合模式:以家具生产为例 [推广有奖]

  • 0关注
  • 0粉丝

等待验证会员

学前班

40%

还不是VIP/贵宾

-

威望
0
论坛币
0 个
通用积分
0
学术水平
0 点
热心指数
0 点
信用等级
0 点
经验
20 点
帖子
1
精华
0
在线时间
0 小时
注册时间
2018-1-30
最后登录
2018-1-30

楼主
张凯max 发表于 2025-12-10 11:36:36 |AI写论文

+2 论坛币
k人 参与回答

经管之家送您一份

应届毕业生专属福利!

求职就业群
赵安豆老师微信:zhaoandou666

经管之家联合CDA

送您一个全额奖学金名额~ !

感谢您参与论坛问题回答

经管之家送您两个论坛币!

+2 论坛币

在家具生产车间中,常常会遇到这样的情况:一张书桌由多个部分构成,例如桌面、桌腿和抽屉;而抽屉本身又包含抽屉面板、侧板和滑轨等更小的部件。同样,一个衣柜可能由柜体、柜门、隔板以及抽屉组成。这些组成部分可能是独立不可拆分的零件,也可能是由若干子部件组合而成的复杂结构。当需要对这些家具进行统一的生产调度、组装检测或后期维护时,如何设计程序才能既支持单个零件的操作,又能无缝处理复杂的嵌套组件?

C++中的组合模式(Composite Pattern)正是为解决这类“部分-整体”层级问题而生的经典结构型设计模式。

一、组合模式的核心思想

组合模式属于结构型设计模式的一种,其核心理念是定义一个统一的抽象构件接口,该接口适用于两种类型:

  • 叶子构件:不能再进一步分解的基本单元,如桌腿、抽屉面板等;
  • 复合构件:由多个叶子构件或其他复合构件组成的整体,如抽屉、书桌、衣柜等。

通过这一设计,客户端代码可以使用相同的接口来操作任意层级的对象——无论是单一零件还是复杂的组合体,从而实现“整体”与“部分”的透明化处理,无需关心当前操作的是哪一类对象。

在家具生产的语境下,“家具部件”即为抽象构件;基本零件如“柜门”“滑轨”是叶子构件;而“书桌”“带抽屉的组合柜”则属于复合构件。

二、组合模式的结构解析(以家具生产为例)

抽象构件(Component)—— 家具部件接口
定义所有家具部件共有的行为方法,例如生产(Produce)、组装(Assemble)、拆卸(Disassemble)。同时声明用于管理子节点的方法,如Add、Remove。对于叶子节点而言,这些管理方法可选择空实现或抛出异常。

叶子构件(Leaf)—— 基本家具零件
实现抽象构件接口,但不包含任何子部件。因此,Add/Remove等方法无需实际逻辑。典型例子包括桌腿、抽屉侧板、柜门等基础零件。

复合构件(Composite)—— 可组合的家具模块
同样实现抽象构件接口,但在内部维护一个子部件集合。在执行生产或组装操作时,会递归调用其所有子部件的对应方法,并提供具体的添加与删除子项逻辑。例如“抽屉”由面板和滑轨构成,“书桌”由桌面、桌腿和多个抽屉构成。

客户端(Client)—— 生产调度系统
仅依赖抽象构件接口与各类部件交互,完全不需要判断对象的具体类型,即可完成统一的流程控制与任务调度。

三、C++代码实现示例(基于家具生产场景)

以下将展示如何使用C++实现上述组合模式的应用,涵盖抽象基类、叶子类、复合类及客户端逻辑。

1. 头文件与抽象构件定义
定义公共接口类 FurnitureComponent,声明通用操作方法和子节点管理接口。

#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>

// 抽象构件:家具部件接口
class FurnitureComponent {
public:
    // 虚析构函数,确保子类析构正常调用
    virtual ~FurnitureComponent() = default;

    // 生产部件
    virtual void Produce() const = 0;

    // 组装部件(叶子构件可仅表示自身完成,复合构件需组装子部件)
    virtual void Assemble() const = 0;

    // 拆卸部件
    virtual void Disassemble() const = 0;

    // 添加子部件(复合构件实现,叶子构件默认抛出异常)
    virtual void Add(FurnitureComponent* component) {
        throw std::invalid_argument("This component cannot add child components.");
    }

    // 删除子部件(复合构件实现,叶子构件默认抛出异常)
    virtual void Remove(FurnitureComponent* component) {
        throw std::invalid_argument("This component has no child components to remove.");
    }

    // 获取部件名称
    virtual std::string GetName() const = 0;
};

2. 叶子构件实现 —— 基础零件
实现具体叶子类,如 TableLeg(桌腿) 和 DrawerFront(抽屉面板)。由于它们无法再细分,Add/Remove 方法沿用父类默认处理方式(通常抛出异常或忽略)。

// 叶子构件:桌腿(不可拆分的基本零件)
class TableLeg : public FurnitureComponent {
public:
    TableLeg(std::string name) : name_(std::move(name)) {}

    void Produce() const override {
        std::cout << "正在生产基本零件:" << name_ << "(材质:实木,工艺:打磨抛光)" << std::endl;
    }

    void Assemble() const override {
        std::cout << "完成基本零件:" << name_ << "的自检,等待与其他部件组装" << std::endl;
    }

    void Disassemble() const override {
        std::cout << "基本零件:" << name_ << "无需拆卸,直接回收或更换" << std::endl;
    }

    std::string GetName() const override {
        return name_;
    }

private:
    std::string name_; // 部件名称(如"书桌左腿")
};

// 叶子构件:抽屉面板(不可拆分的基本零件)
class DrawerPanel : public FurnitureComponent {
public:
    DrawerPanel(std::string name) : name_(std::move(name)) {}

    void Produce() const override {
        std::cout << "正在生产基本零件:" << name_ << "(材质:实木贴皮,工艺:雕刻拉手)" << std::endl;
    }

    void Assemble() const override {
        std::cout << "完成基本零件:" << name_ << "的自检,等待与抽屉侧板组装" << std::endl;
    }

    void Disassemble() const override {
        std::cout << "基本零件:" << name_ << "无需拆卸,直接回收或更换" << std::endl;
    }

    std::string GetName() const override {
        return name_;
    }

private:
    std::string name_; // 部件名称(如"书桌抽屉前板")
};

3. 复合构件实现 —— 组合式部件
创建 CompositeDrawer(抽屉) 和 Desk(书桌) 等复合类。它们持有子部件列表,在执行 Produce 或 Assemble 时,自动遍历并调用每个子项的相同方法,形成递归处理链。

// 复合构件:抽屉(由抽屉面板、侧板、滑轨等组成)
class Drawer : public FurnitureComponent {
public:
    Drawer(std::string name) : name_(std::move(name)) {}

    // 析构函数:释放所有子部件内存
    ~Drawer() override {
        for (auto* component : children_) {
            delete component;
        }
        children_.clear();
    }

    void Produce() const override {
        std::cout << "=====================" << std::endl;
        std::cout << "开始生产复合部件:" << name_ << ",正在生产其子部件..." << std::endl;
        // 递归生产所有子部件
        for (const auto* component : children_) {
            component->Produce();
        }
        std::cout << "复合部件:" << name_ << "的所有子部件生产完成" << std::endl;
        std::cout << "=====================" << std::endl;
    }

    void Assemble() const override {
        std::cout << "=====================" << std::endl;
        std::cout << "开始组装复合部件:" << name_ << ",正在组装其子部件..." << std::endl;
        // 递归组装所有子部件
        for (const auto* component : children_) {
            component->Assemble();
        }
        std::cout << "完成复合部件:" << name_ << "的整体组装(面板+侧板+滑轨拼接)" << std::endl;
        std::cout << "=====================" << std::endl;
    }

    void Disassemble() const override {
        std::cout << "=====================" << std::endl;
        std::cout << "开始拆卸复合部件:" << name_ << ",正在拆卸其子部件..." << std::endl;
        // 递归拆卸所有子部件
        for (const auto* component : children_) {
            component->Disassemble();
        }
        std::cout << "完成复合部件:" << name_ << "的整体拆卸(拆分面板、侧板、滑轨)" << std::endl;
        std::cout << "=====================" << std::endl;
    }

    void Add(FurnitureComponent* component) override {
        if (component == nullptr) {
            throw std::invalid_argument("Cannot add null component.");
        }
        children_.push_back(component);
        std::cout << "已向" << name_ << "添加子部件:" << component->GetName() << std::endl;
    }

    void Remove(FurnitureComponent* component) override {
        if (component == nullptr) {
            throw std::invalid_argument("Cannot remove null component.");
        }
        for (auto it = children_.begin(); it != children_.end(); ++it) {
            if (*it == component) {
                std::cout << "已从" << name_ << "移除子部件:" << component->GetName() << std::endl;
                delete *it; // 释放内存
                children_.erase(it);
                return;
            }
        }
        throw std::invalid_argument("Component not found in " + name_);
    }

    std::string GetName() const override {
        return name_;
    }

private:
    std::string name_; // 部件名称(如"书桌主抽屉")
    std::vector<FurnitureComponent*> children_; // 子部件集合
};

// 复合构件:书桌(由桌面、桌腿、抽屉等组成)
class Desk : public FurnitureComponent {
public:
    Desk(std::string name) : name_(std::move(name)) {}

    // 析构函数:释放所有子部件内存
    ~Desk() override {
        for (auto* component : children_) {
            delete component;
        }
        children_.clear();
    }

    void Produce() const override {
        std::cout << "\n=====================" << std::endl;
        std::cout << "【开始生产成品家具:" << name_ << "】" << std::endl;
        // 递归生产所有子部件
        for (const auto* component : children_) {
            component->Produce();
        }
        std::cout << "【成品家具:" << name_ << "的所有子部件生产完成】" << std::endl;
        std::cout << "=====================\n" << std::endl;
    }

    void Assemble() const override {
        std::cout << "\n=====================" << std::endl;
        std::cout << "【开始组装成品家具:" << name_ << "】" << std::endl;
        // 递归组装所有子部件
        for (const auto* component : children_) {
            component->Assemble();
        }
        std::cout << "【完成成品家具:" << name_ << "的整体组装(桌面+桌腿+抽屉拼接固定)】" << std::endl;
        std::cout << "=====================\n" << std::endl;
    }

    void Disassemble() const override {
        std::cout << "\n=====================" << std::endl;
        std::cout << "【开始拆卸成品家具:" << name_ << "】" << std::endl;
        // 递归拆卸所有子部件
        for (const auto* component : children_) {
            component->Disassemble();
        }
        std::cout << "【完成成品家具:" << name_ << "的整体拆卸(拆分桌面、桌腿、抽屉)】" << std::endl;
        std::cout << "=====================\n" << std::endl;
    }

    void Add(FurnitureComponent* component) override {
        if (component == nullptr) {
            throw std::invalid_argument("Cannot add null component.");
        }
        children_.push_back(component);
        std::cout << "已向" << name_ << "添加子部件:" << component->GetName() << std::endl;
    }

    void Remove(FurnitureComponent* component) override {
        if (component == nullptr) {
            throw std::invalid_argument("Cannot remove null component.");
        }
        for (auto it = children_.begin(); it != children_.end(); ++it) {
            if (*it == component) {
                std::cout << "已从" << name_ << "移除子部件:" << component->GetName() << std::endl;
                delete *it; // 释放内存
                children_.erase(it);
                return;
            }
        }
        throw std::invalid_argument("Component not found in " + name_);
    }

    std::string GetName() const override {
        return name_;
    }

private:
    std::string name_; // 家具名称(如"实木书桌")
    std::vector<FurnitureComponent*> children_; // 子部件集合
};

4. 客户端调度逻辑演示
客户端通过指向抽象构件的指针操作整个书桌对象,无论其内部是直接零件还是嵌套结构,均可统一调用接口完成生产流程,展现出高度一致性。

int main() {
    try {
        // 1. 创建叶子构件(基本零件)
        FurnitureComponent* leftLeg = new TableLeg("书桌左腿");
        FurnitureComponent* rightLeg = new TableLeg("书桌右腿");
        FurnitureComponent* frontPanel = new DrawerPanel("书桌抽屉前板");

        // 2. 创建复合构件:抽屉(包含抽屉面板等零件)
        FurnitureComponent* mainDrawer = new Drawer("书桌主抽屉");
        mainDrawer->Add(frontPanel); // 向抽屉添加面板(实际中还可添加侧板、滑轨等)

        // 3. 创建复合构件:书桌(包含桌腿、抽屉等部件)
        FurnitureComponent* solidWoodDesk = new Desk("实木书桌");
        solidWoodDesk->Add(leftLeg);
        solidWoodDesk->Add(rightLeg);
        solidWoodDesk->Add(mainDrawer);

        // 4. 统一调度:生产、组装、拆卸(无需区分部件类型)
        solidWoodDesk->Produce();  // 生产整个书桌(递归生产所有子部件)
        solidWoodDesk->Assemble(); // 组装整个书桌(递归组装所有子部件)
        solidWoodDesk->Disassemble(); // 拆卸整个书桌(递归拆卸所有子部件)

        // 5. 移除一个子部件(演示动态调整)
        solidWoodDesk->Remove(mainDrawer);

        // 6. 再次组装(此时书桌已无抽屉)
        std::cout << "【移除抽屉后,再次组装书桌】" << std::endl;
        solidWoodDesk->Assemble();

        // 7. 释放根节点内存(析构函数会递归释放所有子部件)
        delete solidWoodDesk;
    } catch (const std::exception& e) {
        std::cerr << "错误:" << e.what() << std::endl;
        return 1;
    }
    return 0;
}

四、运行效果与模式优势分析

操作透明性强
客户端无需区分目标是叶子构件还是复合构件,使用同一套接口即可完成对“桌腿”或“整张书桌”的操作,极大简化了调度系统的逻辑复杂度。

结构动态灵活
可通过 Add 和 Remove 方法在运行时动态调整家具配置,比如为书桌增加额外抽屉,或更换不同材质的桌腿,满足个性化定制需求。

扩展性优异
新增零件类型(如 MetalLeg 金属桌腿)或新的组合结构(如 BookshelfDesk 带书架的书桌),只需继承原有接口,无需修改已有客户端代码,符合开闭原则。

递归处理高效便捷
复合构件通过递归机制逐层向下传递操作指令,自动完成整条装配链的生产与组装,避免手动编写多层条件判断语句。

五、适用场景总结

组合模式特别适用于存在树形层级结构、“部分-整体”关系明确且需统一操作的业务场景。除了本文提到的家具制造系统外,还广泛应用于:

  • 文件系统:文件(叶子)与文件夹(容器)的统一访问;
  • 图形界面组件:按钮、文本框等控件作为叶子,面板或窗口作为容器;
  • 菜单系统:菜单项为叶子,子菜单为复合节点,支持嵌套展开。

在C++实现过程中,应注意使用虚析构函数,并在复合构件中实现递归析构,确保所有子对象被正确释放,防止内存泄漏问题。

二维码

扫码加我 拉你入群

请注明:姓名-公司-职位

以便审核进群资格,未注明则拒绝

关键词:Components Component furniture composite argument
相关内容:C++模式设计

您需要登录后才可以回帖 登录 | 我要注册

本版微信群
扫码
拉您进交流群
GMT+8, 2026-1-18 13:51