news 2026/4/29 15:51:33

C++ 抽象工厂模式实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 抽象工厂模式实战指南

以"咖啡店多地区套餐系统"为例,从工厂方法出发,讲解为什么需要抽象工厂模式以及如何实现。


一、从工厂方法到抽象工厂

工厂方法的局限

在工厂方法模式中,每个地区工厂只创建一种产品(咖啡):

CoffeeAbstractFactory*factory=newChinaCoffeeFactory();Coffee*latte=factory->createCoffee("latte");// 只能创建咖啡

现在需求又变了——咖啡店不仅卖咖啡,还卖甜点,而且不同地区的套餐内容不同:

地区咖啡甜点
中国区拿铁 30元蛋黄酥 15元
美国区拿铁 $5提拉米苏 $6

如果用工厂方法,就需要两套独立的工厂(咖啡工厂 + 甜点工厂),彼此之间没有关联,无法保证"中国区工厂一定搭配中国区甜点"。

抽象工厂的解决思路

一个工厂同时创建一组相关产品。每个地区工厂既能创建咖啡,又能创建甜点,保证产品之间的搭配关系。

工厂方法:一个工厂 → 一种产品 抽象工厂:一个工厂 → 一组相关产品(咖啡 + 甜点)

二、类图

Coffee (抽象产品A) Dessert (抽象产品B) | | ChinaLatte USALatte EggYolkPastry Tiramisu \ / \ / \ / \ / AbstractFactory (抽象工厂) ├── createCoffee() └── createDessert() / \ ChinaFactory USAFactory 创建: 创建: ChinaLatte USALatte EggYolkPastry Tiramisu

核心区别:抽象工厂定义了两个创建方法(createCoffee+createDessert),而工厂方法只有一个。


三、项目结构

include/ ├── Coffee.h # 抽象产品A:咖啡基类 ├── ChinaLatte.h # 中国区拿铁(复用工厂方法的类) ├── USALatte.h # 美国区拿铁(复用工厂方法的类) ├── Dessert.h # 抽象产品B:甜点基类(新增) ├── EggYolkPastry.h # 蛋黄酥(新增) ├── Tiramisu.h # 提拉米苏(新增) ├── AbstractFactory.h # 抽象工厂基类(新增) ├── ChinaFactory.h # 中国区工厂(新增) └── USAFactory.h # 美国区工厂(新增) src/ ├── main.cpp ├── ChinaLatte.cpp # 复用 ├── USALatte.cpp # 复用 ├── EggYolkPastry.cpp # 新增 ├── Tiramisu.cpp # 新增 ├── ChinaFactory.cpp # 新增 └── USAFactory.cpp # 新增

四、逐步实现

第 1 步:定义第二种抽象产品 —Dessert.h

咖啡基类Coffee已经有了,现在新增甜点基类,结构完全对称:

// include/Dessert.h#ifndefDESSERT_H#defineDESSERT_H#include<string>usingnamespacestd;classDessert{public:virtualstringgetName()=0;virtualdoublegetPrice()=0;virtual~Dessert(){}};#endif

踩坑记录:文件名拼写错误(Deesert.h多了个 e),但#include写的是"Dessert.h",编译时报找不到文件。文件名一定要和 include 里的一致。

第 2 步:实现具体甜点

EggYolkPastry.h— 蛋黄酥(声明)
#ifndefEGG_YOLK_PASTRY_H#defineEGG_YOLK_PASTRY_H#include"Dessert.h"classEggYolkPastry:publicDessert{public:stringgetName()override;doublegetPrice()override;};#endif
EggYolkPastry.cpp— 蛋黄酥(实现)
#include"EggYolkPastry.h"stringEggYolkPastry::getName(){return"EggYolkPastry";}doubleEggYolkPastry::getPrice(){return15;// 中国区甜点:15元}
Tiramisu.h— 提拉米苏(声明)
#ifndefTIRAMISU_H#defineTIRAMISU_H#include"Dessert.h"classTiramisu:publicDessert{public:stringgetName()override;doublegetPrice()override;};#endif
Tiramisu.cpp— 提拉米苏(实现)
#include"Tiramisu.h"stringTiramisu::getName(){return"Tiramisu";}doubleTiramisu::getPrice(){return6;// 美国区甜点:$6}

第 3 步:定义抽象工厂基类 —AbstractFactory.h

这是抽象工厂模式的核心——工厂接口中定义多个创建方法:

// include/AbstractFactory.h#ifndefABSTRACT_FACTORY_H#defineABSTRACT_FACTORY_H#include"Coffee.h"#include"Dessert.h"classAbstractFactory{public:virtualCoffee*createCoffee(string type)=0;// 创建咖啡virtualDessert*createDessert(string type)=0;// 创建甜点virtual~AbstractFactory(){}};#endif

对比工厂方法

工厂方法的CoffeeAbstractFactory抽象工厂的AbstractFactory
createCoffee()一个方法createCoffee()+createDessert()两个方法
只能创建咖啡同时创建咖啡和甜点

第 4 步:实现具体工厂

ChinaFactory.h— 中国区工厂(声明)
#ifndefCHINA_FACTORY_H#defineCHINA_FACTORY_H#include"AbstractFactory.h"classChinaFactory:publicAbstractFactory{public:Coffee*createCoffee(string type)override;Dessert*createDessert(string type)override;};#endif
ChinaFactory.cpp— 中国区工厂(实现)
#include"ChinaFactory.h"#include"ChinaLatte.h"#include"EggYolkPastry.h"Coffee*ChinaFactory::createCoffee(string type){if(type=="latte")returnnewChinaLatte();returnnullptr;}Dessert*ChinaFactory::createDessert(string type){if(type=="eggyolkpastry")returnnewEggYolkPastry();returnnullptr;}
USAFactory.h— 美国区工厂(声明)
#ifndefUSA_FACTORY_H#defineUSA_FACTORY_H#include"AbstractFactory.h"classUSAFactory:publicAbstractFactory{public:Coffee*createCoffee(string type)override;Dessert*createDessert(string type)override;};#endif
USAFactory.cpp— 美国区工厂(实现)
#include"USAFactory.h"#include"USALatte.h"#include"Tiramisu.h"Coffee*USAFactory::createCoffee(string type){if(type=="latte")returnnewUSALatte();returnnullptr;}Dessert*USAFactory::createDessert(string type){if(type=="tiramisu")returnnewTiramisu();returnnullptr;}

第 5 步:客户端使用

// src/main.cpp#include<iostream>#include<cstdlib>#include"ChinaFactory.h"#include"USAFactory.h"usingnamespacestd;intmain(){// 中国区工厂 → 同时创建咖啡和甜点AbstractFactory*chinaFactory=newChinaFactory();Coffee*chinaCoffee=chinaFactory->createCoffee("latte");Dessert*chinaDessert=chinaFactory->createDessert("eggyolkpastry");cout<<"=== China Combo ==="<<endl;cout<<"Coffee: "<<chinaCoffee->getName()<<" - "<<chinaCoffee->getPrice()<<"yuan"<<endl;cout<<"Dessert: "<<chinaDessert->getName()<<" - "<<chinaDessert->getPrice()<<"yuan"<<endl;cout<<"Total: "<<chinaCoffee->getPrice()+chinaDessert->getPrice()<<"yuan"<<endl;// 美国区工厂 → 同时创建咖啡和甜点AbstractFactory*usaFactory=newUSAFactory();Coffee*usaCoffee=usaFactory->createCoffee("latte");Dessert*usaDessert=usaFactory->createDessert("tiramisu");cout<<"=== USA Combo ==="<<endl;cout<<"Coffee: "<<usaCoffee->getName()<<" - $"<<usaCoffee->getPrice()<<endl;cout<<"Dessert: "<<usaDessert->getName()<<" - $"<<usaDessert->getPrice()<<endl;cout<<"Total: $"<<usaCoffee->getPrice()+usaDessert->getPrice()<<endl;deletechinaCoffee;deletechinaDessert;deletechinaFactory;deleteusaCoffee;deleteusaDessert;deleteusaFactory;system("pause");return0;}

运行结果:

=== China Combo === Coffee: China Latte - 30yuan Dessert: EggYolkPastry - 15yuan Total: 45yuan === USA Combo === Coffee: USA Latte - $5 Dessert: Tiramisu - $6 Total: $11

五、三种工厂模式完整对比

简单工厂工厂方法抽象工厂
工厂数量1 个每个变体 1 个每个变体 1 个
产品种类1 种1 种多种(一组)
创建方式static+ if/else继承 + 多态继承 + 多态
新增产品变体改工厂 if/else加工厂子类加工厂子类
新增产品种类改抽象工厂接口(所有子工厂都要改)
核心价值集中创建逻辑对扩展开放保证产品族搭配一致

什么时候用哪个?

产品少、不怎么变 → 简单工厂 产品有多种变体、经常扩展 → 工厂方法 多种产品需要配套使用 → 抽象工厂

六、抽象工厂的优缺点

优点

  • 保证产品族一致性:中国区工厂一定创建中国区咖啡 + 中国区甜点,不会出现混搭
  • 新增地区方便:加一个JapanFactory,不改现有代码
  • 客户端只依赖抽象接口AbstractFactory*Coffee*Dessert*

缺点

  • 新增产品种类困难:如果要加"小食(Snack)",需要改AbstractFactory接口加createSnack(),所有已有工厂子类都要跟着改——违反开闭原则
  • 类的数量多:每个地区 × 每种产品 = 大量类文件

取舍原则

  • 如果**经常新增地区(产品族变体)**→ 用抽象工厂,因为只需加工厂子类
  • 如果经常新增产品种类→ 不适合抽象工厂,考虑其他模式

七、角色总结

角色本例中职责
抽象产品 ACoffee咖啡的公共接口
抽象产品 BDessert甜点的公共接口
具体产品ChinaLatte,EggYolkPastry,USALatte,Tiramisu各地区的具体产品
抽象工厂AbstractFactory定义创建咖啡+甜点的接口
具体工厂ChinaFactory,USAFactory各地区工厂,创建本地区的产品组合
客户端main()选择工厂,获取配套产品

八、学习路径回顾

简单工厂 → 工厂方法 → 抽象工厂 | | | 1个工厂 N个工厂 N个工厂 1种产品 1种产品 多种产品 if/else 多态 多态 集中管理 易扩展变体 保证搭配一致

三种模式是递进关系,每一种都是为了解决前一种的局限而出现的。理解了这个演进过程,就能在实际项目中根据需求选择合适的模式。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 15:49:26

Winhance中文版:免费Windows系统优化工具,让电脑性能提升50%

Winhance中文版&#xff1a;免费Windows系统优化工具&#xff0c;让电脑性能提升50% 【免费下载链接】Winhance-zh_CN A Chinese version of Winhance. C# application designed to optimize and customize your Windows experience. 项目地址: https://gitcode.com/gh_mirro…

作者头像 李华
网站建设 2026/4/29 15:46:45

ZeroOmega:终极浏览器代理管理解决方案,一键掌控网络访问

ZeroOmega&#xff1a;终极浏览器代理管理解决方案&#xff0c;一键掌控网络访问 【免费下载链接】ZeroOmega Manage and switch between multiple proxies quickly & easily. 项目地址: https://gitcode.com/gh_mirrors/ze/ZeroOmega 在当今复杂的网络环境中&#…

作者头像 李华
网站建设 2026/4/29 15:45:07

赣州靠谱小程序开发团队怎么选?哪家才是你的首选之选?

在数字化浪潮席卷的当下,小程序凭借其便捷性和高效性,成为众多企业拓展业务、提升服务的重要工具。然而,选择一个靠谱的小程序开发团队并非易事,尤其是在赣州这样的市场环境中。那么,究竟该如何挑选呢?赣州易启科技或许会是你的理想之选。 一、技术实力是基础 1. 开发经…

作者头像 李华
网站建设 2026/4/29 15:45:05

OpenClaw v2.6.6:一键部署AI智能体新时代

前言 随着AI智能体在本地化应用的快速普及&#xff0c;私有化部署、数据安全保障及低门槛落地已成为核心考量标准。开源轻量化AI智能体OpenClaw最新发布的v2.6.6版本实现了全面升级&#xff0c;显著提升了环境适配性、服务稳定性以及模型集成度。新版特别优化了Windows系统的一…

作者头像 李华
网站建设 2026/4/29 15:43:44

别再乱调PID了!用Python画出PI控制器的收敛区域图(附代码)

用Python可视化PI控制器参数收敛域&#xff1a;工程调参的图形化利器 调试PI控制器时&#xff0c;面对密密麻麻的参数组合&#xff0c;你是否曾陷入"调参地狱"&#xff1f;当系统响应出现振荡或发散&#xff0c;传统试错法不仅效率低下&#xff0c;还可能错过最优参数…

作者头像 李华
网站建设 2026/4/29 15:43:39

告别格式焦虑:3步搞定南京信息工程大学毕业论文排版

告别格式焦虑&#xff1a;3步搞定南京信息工程大学毕业论文排版 【免费下载链接】NUIST_Bachelor_Thesis_LaTeX_Template 南京信息工程大学本科生毕业论文 LaTeX 模板 项目地址: https://gitcode.com/gh_mirrors/nu/NUIST_Bachelor_Thesis_LaTeX_Template 还在为毕业论文…

作者头像 李华