模式盘点
模式盘点
ZEROKO14各种模式详解
-
关注点: 线程/任务 如何协作
解决的是:同一进程内,多执行单元如何安全、高效地跑
写“稳定程序”的根基
-
关注点: 模块如何通信
解决的是:一个系统内部,职责如何拆分、组件如何协作
“系统不烂、不乱”的关键
-
解决的是:进程与进程之间如何解耦、可靠地传递消息
关注点: 进程如何通信
企业集成模式(Enterprise Integration Patterns)
EIP,Martin Fowler 那套
消息模式的“工业级全集”
关注点
- 企业系统之间如何可靠集成
- 异构系统
- 事务、幂等、顺序、容错
-
关注点:不可靠网络上的一致性与可用性
解决 CAP、可用性、容错
-
关注点:云环境下的弹性与成本
-
这是“踩坑合集”,非常重要
[[设计模式|设计模式]]
主要是思想,考试常考
只关心三件事:对象如何创建 / 组合 / 协作
针对的是单线程、同步调用下的开发思想
模式之间的关系
1 | ┌──────────────┐ |
并发模式
| 模式 | 描述 | 应用场景 |
|---|---|---|
| 生产者消费者 | 缓冲队列解耦生产者和消费者 | 任务队列、日志处理 |
| 读写锁 | 读共享,写互斥的锁机制 | 缓存系统、配置管理 |
| 线程池 | 复用线程,避免频繁创建销毁 | Web服务器、数据库连接池 |
| 领导者追随者 | 一个线程处理事件,其他线程等待 | 高性能网络服务器 |
| 反应器模式 | 事件驱动,多路复用I/O | Nginx、Netty、Node.js |
| 主动对象 | 异步方法调用,分离方法调用和执行 | 异步任务处理 |
| 屏障模式 | 同步多个线程的执行点 | 并行计算、分阶段处理 |
| 双重检查锁定 | 减少同步开销的延迟初始化 | 单例模式实现 |
架构模式
| 模式 | 描述 | 应用场景 |
|---|---|---|
| 分层架构 | 系统分为多层,每层有明确职责 | 传统企业应用 |
| MVC/MVVM | 分离数据、视图、控制逻辑 | Web应用、桌面应用 |
| 微服务架构 | 小型、自治的服务组成系统 | 大型分布式系统 |
| 事件驱动架构 | 组件通过事件通信,松耦合 | 实时系统、消息系统 |
| 管道过滤器 | 数据流经一系列处理器 | 编译器、ETL工具 |
| CQRS | 分离命令和查询职责 | 复杂业务系统 |
| 六边形架构 | 业务逻辑为核心,适配器处理外部交互 | 领域驱动设计 |
| 服务网格 | 基础设施层处理服务间通信 | 云原生应用 |
消息模式
| 模式 | 描述 | 应用场景 |
|---|---|---|
| 发布订阅 | 消息发送给所有订阅者 | 事件通知、广播 |
| 点对点队列 | 消息只被一个消费者处理 | 任务分发、负载均衡 |
| 请求-响应 | 同步等待回应的通信 | RPC调用、API调用 |
| 管道过滤器 | 消息流经处理链 | 数据处理管道 |
| 消息路由器 | 根据内容路由到不同目标 | 消息分发、条件处理 |
| 消息转换器 | 转换消息格式 | 系统集成 |
| 竞争消费者 | 多个消费者竞争处理消息 | 负载均衡 |
| 消息聚合器 | 收集相关消息后统一处理 | 批量处理 |
工程实例
- MQTT
- RabbitMQ
- ZeroMQ
- Redis Pub/Sub
发布订阅模式
在软件架构中,这个模式通常包含三个部分:
- 发布者 (Publisher):产生消息或事件的对象。它把消息发送给“调度中心”,而不直接发给具体的接收方。
- 调度中心/消息代理 (Broker / Event Bus / Message Queue):这是最重要的中间件。它维护一份“谁订阅了什么话题”的清单。当收到发布者的消息时,它负责把消息分发给所有订阅了该话题的订阅者。
- 订阅者 (Subscriber):对某类消息感兴趣的对象。它向“调度中心”注册自己,告诉中心:“如果有关于‘体育’的消息,请通知我。”
它解决了什么问题?(核心优势)
最主要的作用是 解耦 (Decoupling)。
- 空间解耦:发布者和订阅者不需要知道对方的IP地址或存在。
- 时间解耦:发布者发消息时,订阅者甚至可以不在线(如果配合消息队列使用)。
- 可扩展性:如果你想增加一个新的功能(例如:有人下单后,不仅要发邮件,还要发短信),你只需要新增一个“短信订阅者”即可,完全不需要修改“下单发布者”的代码。
案例代码
C++为例
1 |
|
代码解析 (针对 C++ 特性)
std::unordered_map<string, vector<Handler>>:
- 这是发布订阅模式的灵魂。它是一个字典,Key 是“话题”,Value 是“一群等待通知的人”
- 逻辑:如果是
Map["A"],里面存的就是所有关心话题 A 的函数指针列表。std::function<void(const string&)>:
- 作用:类型擦除
- 它让你可以把普通函数、静态函数、甚至 Lambda 表达式都当成同一个东西存进
vector里。这对于 C++ 实现回调至关重要(类似于你熟悉的 C#Action<string>)Lambda 表达式 [](...) { ... }:
- 允许我们在
main函数里直接定义订阅者的行为,而不需要专门去写一个Subscriber类,极大地精简了代码
MQTT
MQTT实现双向通信的关键:
- 每个客户端都有双重身份:既是发布者,又是订阅者
- 通过主题(topic)路由:客户端订阅感兴趣的主题
- Broker负责转发:不关心谁发布,只根据主题转发
- 客户端可以互相通信:
企业集成模式
| 类别 | 模式 | 描述 |
|---|---|---|
| 消息构造 | 命令消息、事件消息、文档消息 | 定义消息类型和内容 |
| 消息路由 | 内容路由器、消息过滤器、动态路由器 | 控制消息流向 |
| 消息转换 | 消息转换器、信封包装器、内容丰富器 | 转换消息格式和内容 |
| 消息端点 | 消息网关、服务激活器、轮询消费者 | 连接应用和消息系统 |
| 系统管理 | 消息存储、智能代理、测试消息 | 监控和维护 |
Kafka / ESB / 企业总线都在这里
分布式系统模式
- 一致性模式:2PC、Paxos、Raft
- 缓存模式:写穿、写回、旁路缓存
- 容错模式:熔断器、重试、限流、降级
- 服务发现:客户端发现、服务端发现
云设计模式
- 大使模式(Ambassador)
- 挎斗模式(Sidecar)
- 后端聚合(Backends for Frontends)
- 重试模式
- 健康端点监控
反模式(要避免的)
- 大泥球(Big Ball of Mud)
- 上帝对象(God Object)
- 过早优化
- 循环依赖
- 硬编码