📋 摘要
- C++ 设计模式面试高频问答,每题保留回答重点与扩展知识
- 详细原理解析与代码示例见 03-Resources/cpp/C++ 设计模式
- 持续补充中
1. 六大设计原则(SOLID)是什么?
📋 回答重点
- SOLID 是五个面向对象设计原则:单一职责 SRP、开闭 OCP、里氏替换 LSP、接口隔离 ISP、依赖倒置 DIP,中文语境再加迪米特法则共「六大原则」。
- SRP:一个类只负责一件事,只有一个引起它变化的原因。
- OCP:对扩展开放、对修改关闭——加功能不改旧代码。
- LSP:子类必须能完全替换父类,不破坏程序正确性。
- ISP:接口小而专,客户端不依赖它用不到的方法。
- DIP:高层与低层都依赖抽象,不依赖具体实现;迪米特法则即「最少知识原则」。
扩展知识
- OCP 是「目标」,SRP/LSP/ISP/DIP 是达成它的「手段」,回答时点出这个递进关系是加分项。
- 详细讲解:03-Resources/cpp/C++ 设计模式
2. 单例模式(懒汉/饿汉/线程安全)如何实现?
📋 回答重点
- 保证一个类全局只有一个实例:私有构造函数 + 删除拷贝 + 静态访问方法。
- 懒汉:首次调用才创建;饿汉:main 之前即创建(无线程问题但可能浪费)。
- C++11 起推荐 Meyers 单例——函数内静态局部变量,初始化天然线程安全。
- 双检锁 DCLP 需
std::atomic配合 acquire/release 内存序,现在生产优先用 Meyers。 - 典型应用:配置管理器、日志器、连接池、线程池。
扩展知识
- 易错:忘记
= delete拷贝构造/赋值会导致可复制出第二实例;单例跨 DLL 析构顺序不可控。 - 详细讲解:03-Resources/cpp/C++ 设计模式
3. 简单工厂、工厂方法、抽象工厂的区别?
📋 回答重点
- 三者都是把「对象创建与使用」解耦,区别在抽象层级与扩展方式。
- 简单工厂:一个工厂类 + 一个方法,按参数返回不同产品;加新产品要改工厂(违反 OCP)。
- 工厂方法:每个产品对应一个工厂类,加新产品只需加类,不改旧代码。
- 抽象工厂:创建一组相关/相互依赖的产品族(如 Windows 家族 vs Mac 家族)。
- 一句话记:简单工厂=一个函数造所有;工厂方法=一个工厂造一种;抽象工厂=一个工厂造一族。
扩展知识
- 面试常追问「工厂方法比简单工厂好在哪」——好在新增产品不违反开闭原则。
- 详细讲解:03-Resources/cpp/C++ 设计模式
4. 建造者模式如何实现?
📋 回答重点
- 将复杂对象的构造过程与表示分离,支持分步构建 + 链式调用(fluent interface)。
- 结构:产品 + 抽象建造者 + 具体建造者 + 指挥者(Director 固定组装流程)。
- 关键写法:
.setA().setB().build()链式返回*this。 - 与工厂区别:工厂一步到位造对象,建造者分步骤、参数可组合、有默认值。
- 应用:配置对象、HTTP 请求、SQL 语句、ProtoBuf 消息构造。
扩展知识
- 指挥者可选;参数少、无组合需求时用建造者属过度设计。
- 详细讲解:03-Resources/cpp/C++ 设计模式
5. 原型模式如何实现?
📋 回答重点
- 通过克隆已有对象创建新对象,而非
new,核心是clone()方法。 - 适用创建成本高(初始化耗时、依赖 DB/网络)的对象。
- C++ 借助拷贝构造实现深拷贝;典型结构:原型接口 + 具体类 + 原型注册表按 key 克隆。
- 与工厂区别:工厂是「新造」,原型是「复制模板」。
扩展知识
- 易错:C++ 默认拷贝是浅拷贝,含指针成员必须实现深拷贝,否则双重释放/数据串改。
- 详细讲解:03-Resources/cpp/C++ 设计模式
6. 适配器模式如何实现?
📋 回答重点
- 把类的接口转换成客户端期望的另一个接口,让不兼容的类协同工作。
- C++ 两种实现:类适配器(多继承)与对象适配器(组合),后者更常用。
- 应用:对接第三方库/遗留代码、统一多个相似接口、格式转换。
- 与装饰器/代理都「包一层」,区别在意图:适配器改接口、装饰器加功能、代理控访问。
扩展知识
- 记忆口诀:适配器=「插座转换头」。
- 详细讲解:03-Resources/cpp/C++ 设计模式
7. 装饰器模式如何实现?
📋 回答重点
- 不修改原类,动态给对象叠加职责,且可层层嵌套(如加糖加奶的咖啡)。
- 结构:组件接口 + 具体组件 + 抽象装饰器(既是一个组件又持有一个组件)+ 具体装饰器。
- 与继承对比:继承编译期静态扩展、易类爆炸;装饰器运行期动态组合。
- C++ 输入/输出流(
std::fstream/std::istringstream)本质是装饰器应用。
扩展知识
- 装饰器 vs 组合:都递归树形,但组合管「整体-部分」,装饰器管「叠加职责」。
- 详细讲解:03-Resources/cpp/C++ 设计模式
8. 代理模式如何实现?
📋 回答重点
- 为对象提供替身/占位,控制对它的访问。
- 变体:虚拟代理(延迟加载)、远程代理(RPC 存根)、保护代理(权限)、日志代理。
- 典型例子:大图延迟加载——首次 display 才真正创建 RealImage。
- 与装饰器/适配器区别在意图:代理控制访问、装饰器增强功能、适配器改变接口。
扩展知识
std::shared_ptr的自定义 deleter 也是一种「访问/生命周期控制」,可类比代理思想。- 详细讲解:03-Resources/cpp/C++ 设计模式
9. 外观模式如何实现?
📋 回答重点
- 为复杂子系统提供统一的高层接口,简化客户端调用。
- 结构:一个 Facade 类封装多个子系统对象,暴露简单方法(如电脑 start/shutdown)。
- 应用:复杂库/框架易用入口、分层架构隔离子系统、遗留系统封装。
- 与中介者区别:外观是单向简化入口,中介者是双向协调子系统通信。
扩展知识
- 缺点:外观可能膨胀成「上帝对象」;过度封装会失去灵活性。
- 详细讲解:03-Resources/cpp/C++ 设计模式
10. 桥接模式如何实现?
📋 回答重点
- 将抽象部分与实现部分分离,两者可独立变化,核心是「组合代替继承」。
- 结构:Abstraction(形状)持有 Implementor(颜色),避免 n×m 类爆炸。
- 应用:两个独立变化维度(形状+颜色、设备+操作系统)、运行时切换实现。
- 与策略模式结构极像,区别:桥接是结构性(分离抽象与实现),策略是行为性(切换算法)。
扩展知识
- 加分点:明确指出「变化的维度」是识别桥接模式的关键。
- 详细讲解:03-Resources/cpp/C++ 设计模式
11. 组合模式如何实现?
📋 回答重点
- 将对象组织成树形结构,统一处理单个对象与组合对象(文件与文件夹)。
- 结构:统一 Component 接口 + Leaf(叶子)+ Composite(组合,含 children 集合)。
- Composite 的 operation 递归调用子节点。
- 应用:文件系统、UI 控件树、菜单树、AST 语法树。
扩展知识
- 与装饰器都递归,但组合关注「整体-部分结构」,让客户端不区分「一还是多」。
- 详细讲解:03-Resources/cpp/C++ 设计模式
12. 观察者模式如何实现?
📋 回答重点
- 定义一对多依赖,被观察者(Subject)状态变化时自动通知所有观察者(Observer)。
- 结构:Subject 维护观察者列表,提供 attach/detach/notify;Observer 实现 update。
- 应用:事件驱动、GUI 事件、消息订阅、数据变化联动。
- 常见坑:通知中删除观察者导致悬空指针、回调里再触发通知造成死循环。
扩展知识
- C++ 可用
std::weak_ptr或「先拷贝快照再通知」规避悬空指针问题。 - 详细讲解:03-Resources/cpp/C++ 设计模式
13. 策略模式如何实现?
📋 回答重点
- 定义一系列算法并封装成可互换对象,让算法独立于客户端变化。
- 结构:策略接口 + 具体策略(QuickSort/MergeSort)+ 上下文(Sorter 持有策略)。
- 运行时可
setStrategy切换,消除大量 if-else。 - 与状态模式结构像,区别:策略是客户端主动选算法,状态是对象自身状态驱动。
扩展知识
- C++ 中
std::function/函数指针可替代小型策略,减少类数量。 - 详细讲解:03-Resources/cpp/C++ 设计模式
14. 模板方法模式如何实现?
📋 回答重点
- 父类定义算法骨架,可变步骤延迟到子类实现,子类只填空不改流程。
- 结构:父类非虚方法定流程 + protected 纯虚「钩子」方法由子类实现。
- 体现「好莱坞原则」:Don’t call us, we’ll call you(框架调用你)。
- 与策略区别:模板方法用继承(编译期定骨架),策略用组合(运行期换算法)。
扩展知识
- 骨架方法常加
final防止子类重写整体流程。 - 详细讲解:03-Resources/cpp/C++ 设计模式
15. 责任链模式如何实现?
📋 回答重点
- 多个处理器串成链,请求沿链传递,直到某个处理器处理(或都不处理)。
- 结构:Handler 持有 next 指针,自己不处理则调用
Handler::handle(request)传给下一个。 - 应用:审批流、日志分级、HTTP 中间件、异常处理链。
- 两种变体:拦截式(每个都过,如中间件)与终止式(首个能处理的处理并停止,如审批)。
扩展知识
- 注意请求可能无人处理,需设计兜底逻辑。
- 详细讲解:03-Resources/cpp/C++ 设计模式
16. 状态模式如何实现?
📋 回答重点
- 对象内部状态改变时改变行为,把每个状态封装成独立类。
- 结构:State 接口 + 具体状态 + Context 持有当前状态,request 委托给状态处理。
- 应用:订单状态机、TCP 连接状态、工作流引擎。
- 核心收益:消除大量 if-else/switch 条件分支。
扩展知识
- 易错:状态对象间互相引用会造成耦合,应由 Context 统一负责状态切换。
- 详细讲解:03-Resources/cpp/C++ 设计模式
17. 命令模式如何实现?
📋 回答重点
- 把请求封装成对象,支持参数化、排队、日志、撤销/重做。
- 结构:Command 接口(execute + undo)+ 具体命令 + 接收者 + 调用者(Invoker 维护历史栈)。
- 应用:编辑器撤销/重做、任务队列、GUI 按钮、事务回滚。
- 本质是「回调/函数对象的面向对象化」。
扩展知识
- 轻量场景可用
std::function或 lambda 代替;需撤销/队列时用命令对象更合适。 - 详细讲解:03-Resources/cpp/C++ 设计模式
18. 迭代器模式如何实现?
📋 回答重点
- 顺序访问聚合对象元素而不暴露内部表示。
- 核心:
begin()/end()+operator+++operator*(实现指针语义)。 - C++ STL 已内置迭代器,配合泛型算法实现容器与算法彻底解耦。
- 应用:自定义容器、遍历树/图等复杂结构、统一遍历接口。
扩展知识
- 加分点:提到 STL 迭代器分类——输入/输出/前向/双向/随机访问。
- 详细讲解:03-Resources/cpp/C++ 设计模式
19. 享元模式如何实现?
📋 回答重点
- 共享不可变的内在状态,大量减少内存占用。
- 内在状态可共享、不变(如字体名称+字号);外在状态随场景变化(如位置 x,y)由客户端传入。
- 结构:享元对象 + 享元工厂(按内在状态 key 缓存复用)。
- 应用:文字排版、游戏粒子、缓存池。
扩展知识
- 共享对象只读则天然线程安全;拆状态会增加复杂度。
- 详细讲解:03-Resources/cpp/C++ 设计模式
20. 中介者、备忘录、访问者模式各解决什么问题?
📋 回答重点
- 中介者:解决多对象网状通信的耦合爆炸,所有交互都走中间人,变成星形结构(聊天室、MVC Controller、机场塔台)。
- 备忘录:解决对象状态快照与恢复(撤销),在不破坏封装前提下保存/恢复状态。
- 访问者:在不修改元素类的前提下为对象结构添加新操作,用双重分派实现。
- 备忘录 vs 命令实现撤销:备忘录存快照(省逻辑占内存),命令重放逆操作(省内存需可逆)。
扩展知识
- 访问者适合「元素稳定、操作多变」(如编译器 AST);新增元素会违反开闭原则,需改所有 Visitor。
- 详细讲解:03-Resources/cpp/C++ 设计模式