c++中如何实现工厂模式_c++简单工厂与抽象工厂实现步骤【详解】
技术百科
冰火之心
发布时间:2026-01-16
浏览: 次 应使用工厂而非new直接创建对象,因new硬编码导致调用方与具体类强耦合,更换实现需修改多处;工厂将构造逻辑集中,上层仅依赖接口,增删子类不影响业务代码。
为什么不用 new 直接创建对象而要用工厂
因为硬编码 new Derived() 会让调用方和具体类强耦合,一旦要换实现(比如从 MySQLLogger 切到 FileLogger),就得改所有 new 地方。工厂把“怎么造”收拢到一处,上层只依赖接口或基类指针,后续增删子类不波及业务代码。
简单工厂:一个函数返回不同子类指针
它不是 GoF 23 种设计模式之一,但最易理解,适合产品种类少、不常扩展的场景。核心是用参数控制构造逻辑,返回统一基类指针。
常见错误:返回栈对象地址、忘记虚析构、参数类型不安全(比如用 int 枚举易错且难维护)。
- 基类必须有
virtual ~Base() = default;,否则通过基类指针 delete 派生对象会未定义行为 - 推荐用
std::string或枚举类(enum class)作参数,比裸int更可读、类型安全 - 工厂函数内部用
if-else或switch分支,别用宏或全局变量拼类型名
class Product { public: virtual ~Product() = default; virtual void operation() = 0; };
class ConcreteA : public Product { public: void operation() override { std::cout << "A\n"; } };
class ConcreteB : public Product { public: void operation() override { std::cout << "B\n"; } };
enum class ProductType { A, B };
std::unique_ptr createProduct(ProductType type) {
switch (type) {
case ProductType::A: return std::make_unique();
case ProductType::B: return std::make_unique();
default: throw std::invalid_argument("unknown product type");
}
}
抽象工厂:解决“一族产品”的创建问题
当系统需要创建多个相关或相互依赖的对象(比如 Windows 风格控件 + 渲染器,macOS 风格控件 + 渲染器),就不能靠一个简单工厂了。抽象工厂定义接口,由具体工厂实现——每个具体工厂负责一整套配套子类的创建。
容易踩的坑:误把抽象工厂当成“多个简单工厂的集合”,其实关键在“族”的约束;另外,C++ 中抽象工厂接口通常返回 std::unique_ptr 或原始指针,但必须确保调用方清楚所有权归属。
- 抽象工厂类本身是纯接口(全
virtual函数),不包含状态 - 每个具体工厂(如
WinFactory、MacFactory)继承它,并实现所有创建函数 - 产品之间要有逻辑关联性,比如
Button和Checkbox必须来自同一个工厂,否则 UI 风格不一致
class Button { public: virtual ~Button() = default; virtual void paint() = 0; };
class Checkbox { public: virtual ~Checkbox() = default; virtual void render() = 0; };
class GUIFactory {
public:
virtual std::unique_ptr
什么时候该选哪种工厂
简单工厂够用就别上抽象工厂——后者增加至少 3 倍类数量(抽象工厂接口、N 个具体工厂、M 个产品族)。但若已有多个产品需协同工作,或者未来明确要支持多平台/多后端,抽象工厂的扩展成本反而更低。
真正麻烦的是“半抽象”场景:比如产品种类固定,但每种产品又有多个变体(如 EncryptedLogger / PlainLogger)。这时往往得组合策略模式或模板工厂,而不是硬塞进抽象工厂层级里。
# 的是
# 多个
# 又有
# 要有
# windows
# 已有
# 会让
# 要用
# 什么时候
# ui
# default
# go
# 对象
# macos
# c++
# String
# if
# int
# class
# 编码
# 指针
# 子类
# 接口
# 为什么
# 栈
# delete
# 继承
# switch
# mysql
# enum
# 全局变量
# checkbox
# 渲染器
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php在Linux怎么部署_LNMP环境搭建PHP
- Win11怎么关闭搜索历史_Win11清除任务栏搜
- Win11怎么调整屏幕亮度_Windows 11调
- c++中如何求一个数的平方根_c++ sqrt函数
- c++怎么处理多线程死锁_c++ lock_gua
- Win11怎么设置ip地址_Windows 11手
- 一文教你快速开通网站LOGO图
- 如何理解Go指针和内存分配关系_Go Pointe
- Win11怎么更改鼠标指针_Windows 11自
- 如何诊断并终止卡死的 multiprocessin
- c++怎么设置线程优先级与cpu亲和性_c++ 多
- Win11怎么快速锁屏_Win11一键锁屏快捷键W
- Win11怎么查看显卡温度 Win11任务管理器查
- 如何在 PHP 单元测试中正确模拟带方法的图像处理
- Win11怎么更改盘符_Win11磁盘管理修改驱动
- PHP cURL GET请求:正确设置认证与自定义
- 如何在Mac上搭建Golang开发环境_使用Hom
- 如何在Golang中定义接口_抽象方法和多态实现
- php中::能访问全局变量吗_全局作用域与类作用域
- Python抽象类与接口设计_规范说明【指导】
- c++如何使用std::bitset进行位图算法_
- VSC怎么快速定位PHP错误行_错误追踪设置法【方
- Windows10系统更新错误0x80070002
- windows如何测试网速_windows系统网络
- php订单日志怎么记录物流_php记录订单物流变更
- c++中的std::conjunction和std
- mac怎么打开终端_MAC终端Terminal使用
- mac怎么退出id_MAC退出iCloud账号与A
- 如何使用Golang recover捕获panic
- 微信短链接怎么还原php_用浏览器开发者工具抓包获
- Dapper的Execute方法的返回值是什么意思
- Windows 11无法安全删除U盘提示设备正在使
- 如何使用Golang进行HTTP服务性能测试_测量
- 使用类变量定义字符串常量时的类型安全最佳实践
- Python文本编码与解码_跨平台解析说明【指导】
- Win11怎么看电池循环次数_Win11笔记本电池
- Windows Defender扫描失败怎么办_安
- win11如何清理传递优化文件 Win11为C盘瘦
- 如何使用Golang实现多重错误处理_Golang
- Windows电脑如何进入安全模式?(多种按键方法
- c++怎么操作redis数据库_c++ hired
- Python函数参数高级用法_默认值与可变参数解析
- Windows如何使用注册表查找和删除项?(reg
- Win10如何卸载自带Edge_Win10彻底卸载
- Win11怎么设置默认图片查看器_Windows1
- 如何使用Golang反射将map转换为struct
- C++中的协变与逆变是什么?C++函数指针与返回类
- Windows10系统服务优化指南_Win10禁用
- XML的“混合内容”是什么 怎么用DTD或XSD定
- Python安全爬虫设计_IP代理池与验证码识别策

QQ客服