架构模式与设计模式
许多开发者将架构模式与设计模式混为一谈,实际上二者关注的抽象层次截然不同:设计模式解决类与对象级别的协作问题,架构模式解决系统级别的组织与交互问题。本文系统梳理二者的本质差异,并深入讲解六大经典架构模式。
1. 本质区别
1.1 关注点
| 维度 | 设计模式 (GoF 23) | 架构模式 |
|---|---|---|
| 抽象层次 | 类/对象 | 子系统/模块/服务 |
| 影响范围 | 单个模块内部 | 整个系统的拓扑结构 |
| 代码量 | 数十行到数百行 | 数千行到数万行 |
| 演变更本 | 较低(重构类关系) | 极高(改动系统骨架) |
| 典型数量 | 约 23 个经典模式 | 约 10+ 大架构模式 + N 种变体 |
| 示例 | 工厂、单例、观察者 | 分层、微服务、事件溯源 |
1.2 关系图
单一职责原则(SOLID)
↓ 指导
设计模式(GoF 23)←→ 架构模式(10+)
↓ 解决问题层次不同
设计模式 ≈ 房屋内部的家具摆放方式
架构模式 ≈ 房屋本身的结构布局(几室几厅、承重墙位置)
2. 六大经典架构模式
2.1 分层架构(Layered Architecture)
最经典、最广泛使用的架构模式,将软件按职责垂直划分为多个层次。
┌──────────────────────────┐
│ 表示层(Presentation) │ ← UI、API、控制器
├──────────────────────────┤
│ 业务逻辑层(Business) │ ← 领域模型、服务编排
├──────────────────────────┤
│ 数据访问层(Data) │ ← DAO、Repository
├──────────────────────────┤
│ 数据库层(Database) │ ← 关系型/NoSQL
└──────────────────────────┘
依赖规则:上层可调用下层,下层不可反向依赖
跨层通信:建议通过 DTO 进行数据传输
变体:N-Tier(物理分层)
Web 服务器(Tier 1)→ 应用服务器(Tier 2)→ 数据库服务器(Tier 3)
每台服务器可独立扩展,使用网络协议通信而非内存调用
适用场景:传统企业应用(ERP、CRM)、中小型 Web 应用、初学者入门项目。
常见反模式:
- ** spaghetti 式分层**:上层直接绕过中间层调用底层
- 贫血领域模型:业务逻辑全在 Service 层,Entity 只有 getter/setter
2.2 管道-过滤器(Pipes and Filters)
将数据处理过程分解为一系列独立的过滤组件,通过管道连接。
数据输入 → [过滤器 A] ──管道──→ [过滤器 B] ──管道──→ [过滤器 C] → 数据输出
│ │ │
读取文件 数据转换 写入输出
Unix Shell 示例:
cat log.txt | grep "ERROR" | awk '{print $5}' | sort | uniq -c
读取 过滤错误行 提取第5列 排序 统计频率
适用场景:编译器(词法分析→语法分析→语义分析→代码生成)、音视频处理管道、ETL 数据处理、日志分析系统。
优点:
- 过滤器可独立开发、测试和复用
- 管道支持并行化执行(流式处理)
- 系统扩展简单(新增过滤器即可)
缺点:
- 数据格式需统一(兼容性成本)
- 不适合交互性强、需要状态共享的场景
2.3 微内核/插件架构(Microkernel)
核心系统提供最小化运行环境,功能通过插件动态扩展。
┌─────────────────────────────────┐
│ 插件管理器(Plugin Manager)│
│ ┌──────────┐ ┌──────────┐ │
│ │ 插件 A │ │ 插件 B │ ... │
│ └──────────┘ └──────────┘ │
├─────────────────────────────────┤
│ 核心服务(Core) │
│ - 生命周期管理 │
│ - 事件总线 │
│ - 模块加载器 │
│ - 配置管理 │
└─────────────────────────────────┘
示例:
- IDE(VS Code、IntelliJ)
- 浏览器(Chrome 扩展)
- 游戏引擎(UE4/Unity 插件系统)
- Jenkins(流水线插件)
关键设计决策:
| 维度 | 选择 |
|---|---|
| 插件间通信 | 通过核心事件总线(松耦合)或直接 API 调用(高性能) |
| 隔离机制 | OSGi classloader 隔离 / Docker 容器隔离 / 进程隔离 |
| 部署方式 | 动态热加载 / 重启生效 |
2.4 事件驱动架构(Event-Driven Architecture, EDA)
组件间通过异步事件而非直接调用来通信,实现高度解耦。
┌────────────┐
订单服务 ──事件──→│ 事件总线 │
│ (Kafka/ │
库存服务 ←──订阅───│ RabbitMQ) │
│ │
通知服务 ←──订阅───│ │
└────────────┘
优势:
- 发布者和订阅者互不知晓
- 可独立扩展消费者
- 天然支持事件溯源(Event Sourcing)
三种事件模式:
| 模式 | 说明 | 示例 |
|---|---|---|
| 事件通知 | 只通知发生了某事,不携带详情 | “订单已创建” |
| 事件携带状态 | 包含事件相关的完整数据 | “订单已创建 + 订单详情” |
| 事件溯源 | 以事件序列作为系统状态的唯一来源 | 所有状态变化 = 事件日志 |
缺点与应对:
- 最终一致性:需设计补偿事务(Saga 模式)
- 事件乱序:Kafka 分区保证局部有序,全局有序需额外设计
- 调试困难:请求链路跨越多个服务 → 分布式追踪必配
2.5 微服务架构(Microservices)
将单一应用拆分为一组小型服务,每个服务独立部署、独立扩展。
API Gateway
│
├──→ 用户服务(Users) —→ 用户数据库
├──→ 订单服务(Orders) —→ 订单数据库
├──→ 库存服务(Inventory)—→ 库存数据库
├──→ 支付服务(Payment) —→ 支付数据库
└──→ 通知服务(Notify) —→ 消息队列
拆分策略:
| 策略 | 依据 | 优点 | 风险 |
|---|---|---|---|
| 按业务领域(DDD) | 限界上下文 | 天然高内聚 | 需深入领域理解 |
| 按功能(CRUD) | 实体类型 | 直观简单 | 易过小导致管理成本 |
| 按团队(康威定律) | 组织结构 | 团队自治 | 技术栈可能碎片化 |
何时不选微服务:
- 团队 < 20 人
- 请求 QPS < 1000
- 没有自动化部署/监控基础设施
- 业务领域边界不清晰
2.6 空间架构/基于网格的架构(Space-Based Architecture)
消除中心数据库瓶颈,将数据和处理单元分布到网格节点。
┌─────────────────────────────────────────┐
│ 负载均衡器(Load Balancer) │
└─────────────────────────────────────────┘
│ │ │
┌────────┐ ┌────────┐ ┌────────┐
│ 处理单元│ │ 处理单元│ │ 处理单元│
│ ┌────┐ │ │ ┌────┐ │ │ ┌────┐ │
│ │内存│ │ │ │内存│ │ │ │内存│ │ ← 数据缓存在内存
│ │Cache│ │ │ │Cache│ │ │ │Cache│ │
│ └────┘ │ │ └────┘ │ │ └────┘ │
└────────┘ └────────┘ └────────┘
│ │ │
└─────────────────────────────────────────┘
│ 数据总线/消息队列(Data Grid) │
└─────────────────────────────────────────┘
适用场景:高并发读写系统(证券交易、在线游戏、实时竞价)。
代表产品:Hazelcast、Apache Ignite、GigaSpaces。
3. 架构模式选择决策树
是否需要处理大量并发用户?
├── 是 → 数据量极大?
│ ├── 是 → 空间架构 / 微服务 + CQRS
│ └── 否 → 微服务 / 事件驱动
└── 否 → 数据流处理为主?
├── 是 → 管道-过滤器
└── 否 → 需要高度可扩展性?
├── 是 → 微内核 / 插件架构
└── 否 → 分层架构(默认选择)
4. 架构模式组合拳
实际系统很少只用一种架构模式,通常是多种模式组合。
| 系统类型 | 模式组合 |
|---|---|
| 电商平台 | 分层(单体阶段)→ 微服务 + 事件驱动(演进阶段) |
| 银行核心系统 | 分层 + 微内核(插件化的业务规则) |
| 实时交易系统 | 空间架构 + 事件驱动 |
| 数据中台 | 管道-过滤器(ETL)+ 事件驱动(数据变更流) |
| SaaS 平台 | 多租户分层 + 微服务 + 微内核(可插拔模块) |
5. 总结
架构模式:系统骨架(how to organize the system)
设计模式:模块细节(how to organize classes/objects within a module)
关系:架构模式 → 划定子系统边界 → 子系统内用设计模式实现细节
两者互补,缺一不可。只懂设计模式而忽视架构,会导致"精致的烂泥潭";
只谈架构而忽视设计模式,会导致"空中楼阁无法落地"。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。