news 2026/2/6 7:12:54

C++ 设计模式之工厂模式(Factory)和面试问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++ 设计模式之工厂模式(Factory)和面试问题

工厂模式(Factory)


一、问题背景:为什么需要工厂模式

1. 直接new带来的问题

典型代码:

Shape*s=newCircle(10);

问题不在于new,而在于:

  • 类型强耦合
  • 违反开闭原则(OCP)
  • 创建逻辑分散
  • 难以替换实现 / 测试 / 配置化

一旦对象创建逻辑变复杂(参数、配置、平台差异),调用者将被迫了解过多细节。


2. 本质问题抽象

“谁负责决定创建哪一个具体类型?”

  • 调用者?
  • 对象自己?
  • 专门的创建者(Factory)?

二、工厂模式的核心思想

1. 定义

将对象的创建与使用解耦,由专门的工厂负责实例化具体对象。

从依赖关系角度看:

调用方 → 抽象接口 工厂 → 具体实现

2. 设计目标

  • 消除对具体类型的直接依赖
  • 集中管理对象创建逻辑
  • 支持运行期多态创建
  • 为扩展而非修改而设计

三、工厂模式的三种典型形式

模式核心关注点复杂度
简单工厂集中创建逻辑
工厂方法延迟具体类型决定⭐⭐
抽象工厂产品族一致性⭐⭐⭐

四、简单工厂(Simple Factory)

严格来说不是 GoF 设计模式,但在工程中极其常见。

1. 结构

Factory → switch / if → ConcreteProduct

2. 示例

抽象产品
classShape{public:virtual~Shape()=default;virtualvoiddraw()const=0;};
具体产品
classCircle:publicShape{public:voiddraw()constoverride{std::cout<<"Draw Circle\n";}};classSquare:publicShape{public:voiddraw()constoverride{std::cout<<"Draw Square\n";}};
工厂
enumclassShapeType{Circle,Square};classShapeFactory{public:staticstd::unique_ptr<Shape>create(ShapeType type){switch(type){caseShapeType::Circle:returnstd::make_unique<Circle>();caseShapeType::Square:returnstd::make_unique<Square>();default:returnnullptr;}}};

3. 特点分析

优点

  • 使用简单
  • 创建逻辑集中

缺点

  • 新增类型必须修改工厂
  • switch不可避免 → 违反 OCP

五、工厂方法(Factory Method)

将“创建哪种产品”的决定权下放给子类

1. 结构

Creator(抽象工厂) └── ConcreteCreator(具体工厂) └── ConcreteProduct

2. 示例

抽象产品
classLogger{public:virtual~Logger()=default;virtualvoidlog(conststd::string&msg)=0;};
具体产品
classFileLogger:publicLogger{public:voidlog(conststd::string&msg)override{std::cout<<"File: "<<msg<<"\n";}};classConsoleLogger:publicLogger{public:voidlog(conststd::string&msg)override{std::cout<<"Console: "<<msg<<"\n";}};
抽象工厂
classLoggerFactory{public:virtual~LoggerFactory()=default;virtualstd::unique_ptr<Logger>create()const=0;};
具体工厂
classFileLoggerFactory:publicLoggerFactory{public:std::unique_ptr<Logger>create()constoverride{returnstd::make_unique<FileLogger>();}};classConsoleLoggerFactory:publicLoggerFactory{public:std::unique_ptr<Logger>create()constoverride{returnstd::make_unique<ConsoleLogger>();}};

3. 特点分析

优点

  • 遵循开闭原则
  • 易于扩展新类型
  • 消除了switch

代价

  • 类数量显著增加
  • 结构复杂度提高

六、抽象工厂(Abstract Factory)

创建“相关或相互依赖的一组对象”

1. 典型应用场景

  • GUI 跨平台(Windows / Linux)
  • 渲染后端(OpenGL / Vulkan)
  • SLAM 中不同传感器产品族

2. 示例结构

AbstractFactory ├── createA() └── createB() ConcreteFactory1 → ProductA1 + ProductB1 ConcreteFactory2 → ProductA2 + ProductB2

3. 示例代码

抽象产品
classButton{public:virtualvoidpaint()=0;virtual~Button()=default;};classCheckbox{public:virtualvoidpaint()=0;virtual~Checkbox()=default;};
抽象工厂
classGUIFactory{public:virtual~GUIFactory()=default;virtualstd::unique_ptr<Button>createButton()=0;virtualstd::unique_ptr<Checkbox>createCheckbox()=0;};
具体工厂
classWindowsFactory:publicGUIFactory{public:std::unique_ptr<Button>createButton()override;std::unique_ptr<Checkbox>createCheckbox()override;};

4. 特点分析

优势

  • 保证产品族一致性
  • 完全隔离具体实现

不足

  • 新增“产品种类”困难
  • 接口膨胀风险

七、C++ 工程化要点

1. 返回裸指针 vs 智能指针

方式适用场景
unique_ptr所有权明确(推荐)
shared_ptr共享生命周期
裸指针极少(非拥有语义)

2. 注册式工厂(消除switch

usingCreator=std::function<std::unique_ptr<Shape>()>;classFactory{public:staticFactory&instance(){staticFactory f;returnf;}voidregisterType(std::string name,Creator c){creators_[name]=std::move(c);}std::unique_ptr<Shape>create(conststd::string&name){returncreators_.at(name)();}private:std::unordered_map<std::string,Creator>creators_;};

优点

  • 插件化
  • 配置驱动
  • 完全符合 OCP

3. 与模板的关系

  • 运行期多态 → 工厂
  • 编译期多态 → 模板

混合方案(CRTP + 工厂)在高性能系统中很常见。


八、常见误用与反模式

  • 为简单对象滥用工厂
  • 工厂类变成“上帝类”
  • 把业务逻辑塞进工厂
  • 用工厂代替依赖注入

九、什么时候用工厂模式

核心判断标准不是“能不能用”,而是**“是否值得引入间接层”**

1. 适合使用的典型信号

(1)对象创建逻辑具有变化性
  • 新类型可能频繁加入

  • 创建规则可能因配置 / 平台 / 环境变化

  • 示例:

    • 不同传感器模型
    • 不同后端(CPU / GPU)
    • 不同日志输出方式

变化点集中在“创建阶段”


(2)调用方不应知道具体类型

如果调用方只关心接口语义:

process(Detector&detector);

而不应关心:

ORBDetector/SuperPointDetector/CustomDetector

工厂是依赖反转的自然载体


(3)对象创建代价高或步骤复杂
  • 需要读取配置
  • 需要资源初始化
  • 需要多阶段构造

此时:

  • new放在业务代码中是结构性污染
  • 工厂可作为生命周期边界

2. 不适合使用的情况

场景原因
类型固定且简单间接层无收益
只创建一次的小对象工厂成本 > 收益
纯值类型(POD)不需要多态
强性能敏感内循环虚函数 + 间接跳转

十、在什么模块中最常见(Where It Appears)

1. 系统架构层面(高频)

(1)模块边界 / 子系统入口
  • 解码器工厂
  • 渲染后端工厂
  • 数据源工厂
App └── Factory └── Subsystem Impl

工厂通常是模块的“门面入口”


2. 中间件与基础设施层(极常见)

模块工厂作用
日志系统Console / File / Network
存储系统Memory / Disk / Cloud
网络TCP / UDP / QUIC
序列化JSON / Protobuf / FlatBuffers

3. SLAM / CV / Robotics(工程经验)

你这个背景下,工厂模式非常常见于:

  • 特征提取器(ORB / SIFT / SuperPoint)
  • 回环检测模块
  • 地图后端优化器
  • 传感器模型(LiDAR / Camera / IMU)

典型原因:

  • 算法频繁替换
  • 实验配置驱动
  • 运行期选择

十一、典型 C++ 写法(Recommended Patterns)

1. 最推荐:注册式工厂 + 智能指针

这是现代 C++ 工程中最常用、扩展性最好的一种。

classBase{public:virtual~Base()=default;};usingCreator=std::function<std::unique_ptr<Base>()>;classFactory{public:staticFactory&instance(){staticFactory f;returnf;}voidregisterCreator(conststd::string&key,Creator c){creators_[key]=std::move(c);}std::unique_ptr<Base>create(conststd::string&key)const{returncreators_.at(key)();}private:std::unordered_map<std::string,Creator>creators_;};

特点

  • switch
  • 完全符合 OCP
  • 支持插件化 / 动态库

2. 静态注册(工程常用技巧)

structRegistrar{Registrar(){Factory::instance().registerCreator("A",[]{returnstd::make_unique<A>();});}};staticRegistrar reg;

常见于

  • 算法注册
  • 模块自动发现
  • Plugin system

3. 模板 + 工厂混合(高性能场景)

template<typenameT>std::unique_ptr<Base>create(){returnstd::make_unique<T>();}

适合:

  • 类型在编译期已知
  • 不需要运行期字符串查找
  • 追求零开销抽象

4. 工厂 + 配置文件(生产系统)

autotype=config["detector"];autodetector=Factory::instance().create(type);

工厂是“配置驱动架构”的关键支点


十二、常见误区(Very Important)

1. 为了“设计模式”而用工厂

错误动机

“这里好像可以用工厂模式”

正确动机

“这里存在变化扩散风险”


2. 工厂类膨胀成上帝对象

反例:

classFactory{public:createA();createB();createC();loadConfig();validate();};

问题:

  • 职责混乱
  • 难以维护
  • 难以测试

工厂只负责创建,不负责业务


3. 用工厂代替依赖注入(DI)

工厂:

  • 负责创建

DI:

  • 负责装配

二者职责不同,但可以配合。


4. 忽视对象生命周期语义

错误:

Base*create();// 所有权不清晰

推荐:

std::unique_ptr<Base>create();

工厂必须明确谁拥有对象


5. 过早抽象

  • 当前只有一个实现
  • 短期内无变化需求

YAGNI原则优先


十三、总结

工厂模式不是为了“少写 new”,
而是为了控制变化的传播路径

选择建议:

  • 类型固定、简单 → 不用工厂
  • 类型可扩展 → 工厂方法
  • 产品族强一致 → 抽象工厂
  • 配置 / 插件驱动 → 注册式工厂

下面给你一份面向中高级 C++ / 系统 / SLAM 岗位的「工厂模式面试问题清单」
不是背定义,而是考理解、考取舍、考工程经验
我按“从浅到深 + 高频考点”组织,并给出标准回答要点(不是死答案)。


C++ 工厂模式 面试问题


一、基础理解类

Q1:什么是工厂模式?它解决了什么问题?

答题要点:

  • 对象创建与使用解耦
  • 消除对具体类型的直接依赖
  • 控制“变化的传播”
  • 本质是依赖反转(DIP)+ 开闭原则(OCP)

工厂模式用于在不修改调用方的情况下,引入或替换具体实现。


Q2:C++ 中常见的工厂模式有哪些?

答题要点:

  • 简单工厂(工程常用,非 GoF)
  • 工厂方法(Factory Method)
  • 抽象工厂(Abstract Factory)

可加一句:

实际工程中,注册式工厂比教科书模式更常见。


Q3:工厂模式和直接new的本质区别?

答题要点:

  • new暴露具体类型
  • 工厂隐藏类型决策
  • 工厂引入了间接层,但换来可扩展性

反问式总结:

如果类型永远不变,就不需要工厂。


二、设计判断类

Q4:什么时候不应该使用工厂模式?

答题要点:

  • 类型固定、不会扩展
  • 对象是值语义(POD)
  • 性能极度敏感的内循环
  • 只有一个实现且短期无变化

关键词:YAGNI、过度设计


Q5:简单工厂为什么不符合开闭原则?

答题要点:

  • 新增类型必须修改switch / if
  • 修改集中在工厂内部
  • 违反“对扩展开放,对修改关闭”

可补充:

工程上可通过注册机制弥补这一问题。


Q6:工厂方法 vs 抽象工厂的核心区别?

答题要点:

对比点工厂方法抽象工厂
关注点单一产品产品族
扩展维度新类型新平台
接口规模

总结:

工厂方法解决“用哪一个”,抽象工厂解决“用哪一套”。


三、C++ 特有问题

Q7:工厂函数应该返回裸指针还是智能指针?

标准答案:

  • 优先返回std::unique_ptr
  • 明确所有权语义
  • 避免内存泄漏

补充说明:

返回裸指针通常意味着“不拥有”,但工厂语义下很少成立。


Q8:为什么现代 C++ 工厂常用std::function+ lambda?

答题要点:

  • 消除样板代码
  • 统一创建接口
  • 支持捕获配置 / 状态
  • 可与注册机制自然结合

加分点:

性能敏感场景可用函数指针或模板替代。


Q9:工厂模式和模板有什么关系?

答题要点:

  • 工厂 → 运行期多态
  • 模板 → 编译期多态
  • 工厂适合配置驱动
  • 模板适合性能敏感、类型固定场景

一句话:

是否需要运行期选择类型,是分界线。


四、工程实战类

Q10:如何在不修改工厂代码的情况下新增类型?

答题要点:

  • 注册式工厂
  • 静态自动注册
  • 插件加载时注册

示例思路:

Factory::instance().registerCreator("ORB",[]{returnstd::make_unique<ORB>();});

Q11:静态注册工厂有哪些坑?

答题要点:

  • 静态初始化顺序问题
  • 链接器裁剪(未引用对象被移除)
  • 动态库加载顺序

对策关键词:

  • 函数内static
  • 显式引用
  • 插件初始化接口

Q12:工厂模式和依赖注入(DI)的关系?

答题要点:

  • 工厂负责“创建”
  • DI 负责“装配”
  • 工厂是 DI 的一种实现手段

一句话:

工厂是机制,DI 是架构思想。


五、进阶/架构类

Q13:工厂模式的性能代价在哪里?

答题要点:

  • 虚函数调用
  • std::function间接调用
  • map 查找

优化手段:

  • 编译期工厂
  • 函数指针
  • 枚举 + 表

Q14:什么时候工厂会演变成反模式?

答题要点:

  • 工厂类承担业务逻辑
  • 工厂知道过多细节
  • 工厂数量爆炸
  • 所有东西都“Factory 化”

关键词:上帝对象


Q15:在 SLAM / 引擎系统中,哪些模块最适合用工厂?

答题要点:

  • 特征提取器
  • 匹配器
  • 优化后端
  • 传感器模型

原因:

  • 算法频繁切换
  • 实验驱动
  • 配置驱动

六、经典“陷阱题”

Q16:shared_ptr适合做工厂返回值吗?

答题要点:

  • 可以,但应谨慎
  • 适合共享生命周期
  • 否则会掩盖所有权设计问题

面试官想听:

默认unique_ptr,必要时才shared_ptr


Q17:为什么不把工厂写成单例?

答题要点:

  • 不是必须
  • 单例会引入全局状态
  • 可测试性下降

成熟回答:

注册式工厂常以单例存在,但这是权衡结果,不是必然。


七、终极总结

工厂模式的价值不在于“创建对象”,
而在于“隔离变化、控制依赖方向”。


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

终极指南:轻松掌握Legacy iOS Kit,让老设备重获新生

终极指南&#xff1a;轻松掌握Legacy iOS Kit&#xff0c;让老设备重获新生 【免费下载链接】Legacy-iOS-Kit An all-in-one tool to downgrade/restore, save SHSH blobs, and jailbreak legacy iOS devices 项目地址: https://gitcode.com/gh_mirrors/le/Legacy-iOS-Kit …

作者头像 李华
网站建设 2026/2/6 21:43:40

不用再写环境配置!BSHM镜像直接开跑

不用再写环境配置&#xff01;BSHM镜像直接开跑 随着图像处理技术的快速发展&#xff0c;人像抠图在电商、视频制作、虚拟现实等场景中变得越来越重要。然而&#xff0c;传统的人像抠图模型部署过程复杂&#xff0c;依赖繁多&#xff0c;尤其是面对 TensorFlow 1.x 与现代 GPU…

作者头像 李华
网站建设 2026/1/29 5:41:21

接地电阻柜适配广泛

接地电阻柜是电力系统核心的接地保护设备&#xff0c;核心作用是通过在系统中性点与大地之间接入限流电阻&#xff0c;实现故障防护与系统稳定保障。其核心构成包括特种合金电阻器、绝缘支撑件、电流互感器、智能监控装置及金属防护柜体&#xff0c;其中电阻器采用耐高温、抗氧…

作者头像 李华
网站建设 2026/2/5 10:55:05

MinerU教育场景应用:试卷数字化系统搭建保姆级教程

MinerU教育场景应用&#xff1a;试卷数字化系统搭建保姆级教程 1. 引言 1.1 教育数字化转型的迫切需求 随着教育信息化进程的不断推进&#xff0c;传统纸质试卷的管理与复用面临诸多挑战。教师在日常教学中需要频繁整理历年真题、模拟卷和课堂练习&#xff0c;而这些资料大多…

作者头像 李华
网站建设 2026/2/3 10:44:30

Hunyuan翻译精度提升:WMT25测试集优化部署案例

Hunyuan翻译精度提升&#xff1a;WMT25测试集优化部署案例 1. 引言&#xff1a;轻量级多语翻译模型的工程挑战 随着全球化内容消费的增长&#xff0c;高质量、低延迟的多语言翻译需求在移动端和边缘设备场景中日益凸显。传统大模型虽具备较强翻译能力&#xff0c;但受限于显存…

作者头像 李华