.NET常见的几种项目架构模式

此帖子于闲来无事中想到过之前面试官问过的问题,勉强答上来了但无法细致说出各自特点和优缺点以及各自使用场景,随根据网上资料做一下备忘记录

本文根据网上资料汇总整理了.NET 开发最常用的5种架构模式:经典三层架构、整洁/洋葱架构、领域驱动设计DDD、CQRS读写分离、微服务架构,清晰对比每层职责、优缺点与适用场景

1.三层架构
这是最经典、最基础的架构模式,也是大多数初学者接触的第一种模式。
d20dc2a9-af04-4e5b-b425-298f9a8d597b

  • 其核心结构:
    • 表现层(UI):处理用户交互(MVC, WPF, API Controllers)
    • 业务逻辑层(BLL):编写核心业务规则
    • 数据访问层(DAL):负责与数据库交互(如 EF Core, Dapper)
    • 实体层(Entities/Models):各层之间传递数据的对象,会被所有层引用
  • 特点:
    • 依赖方向:通常上层依赖下层(UI -> BLL -> DAL),或者通过接口倒置
    • 简单直观:结构清晰,易于理解和上手
    • 线性流程:请求通常自上而下流动
  • 优点:
    • 开发成本低,适合小型团队
    • 每层职责明确
  • 缺点:
    • 业务逻辑往往堆积在BLL的服务类中,实体类只是数据容器
    • 耦合度较高:修改底层数据结构可能波及上层
    • 测试困难:如果不严格依赖接口,层层依赖会导致单元测试难以隔离
  • 适用场景:
    • 简单的 CRUD 应用(管理系统、后台管理)
    • 团队技术栈较浅,需要快速交付项目

2.整洁架构/洋葱架构
整洁架构是组织软件体系结构的原则,可以轻松面对未来的不确定性,方便代码的重构。同时,它可以帮助我们为特定的领域模型构建服务,从而为将来可能的微服务体系结构做好准备。算是目前 .NET 中大型应用的主流选择。
90d8fb23-6a34-4f16-b972-6a4d1f0d8b95

以下是我查看帖子(原贴链接)比较好理解的图片了(为啥会称为洋葱架构)
image

  • 其核心结构:
    • 领域层 (Domain):最内层,包含实体、值对象、领域服务。不依赖任何外部库
    • 应用层 (Application):包含用例、接口定义 (Interfaces)、DTOs。依赖领域层
    • 基础设施层 (Infrastructure):实现应用层的接口(如 EF Core 实现、邮件服务、文件存储)
    • 表现层 (Web API/UI(MVC)):最外层,依赖应用层
  • 关键原则:
    • 依赖倒置:所有依赖指向圆心(内部)。外层依赖内层,内层绝不依赖外层
    • 业务独立:核心业务逻辑不依赖数据库、UI 或框架
  • 特点:
    • 高度解耦,可测试性极强
    • 技术细节(如换数据库、换 UI 框架)不影响核心业务
  • 优点:
    • 长期维护性好:业务逻辑稳定,技术栈可变
    • 单元测试友好:核心层可以完全脱离数据库和 Web 环境进行测试
    • 界限清晰:强制将业务逻辑放在正确的位置
  • 缺点:
    • 样板代码多:需要大量的接口、映射(Mapper)和依赖注入配置
    • 学习曲线陡峭:新接触者容易混淆各层职责
    • 过度设计风险:对于简单项目,显得过于繁琐
  • 适用场景:
    • 中大型企业级应用
    • 业务逻辑复杂且需要长期维护的项目
    • 存在需要更换技术组件(如从 SQL Server 换到 Mongo,或从 MVC 换到 Blazor)的系统

3.领域驱动设计(DDD)
DDD是一种方法论但也是一种面向复杂业务领域的软件开发思想与架构风格,强调 “代码与业务深度对齐”,常与整洁架构结合使用(称为 DDDA,即 DDD + Clean Architecture)。
04dc5ecc-9d95-42fb-967c-db10f6613839

  • 其核心概念:
    • 聚合根 (Aggregate Root):负责维护边界内的数据一致性与对象生命周期,是整个聚合的唯一入口;外部只能通过聚合根访问内部实体,保证数据一致性的边界
    • 实体 (Entity) & 值对象 (Value Object):丰富的领域模型,包含行为而非仅仅是数据。实体:有唯一标识、生命周期,可变化(如订单、用户);值对象:无标识、由属性值定义且不可变(如地址、金额),用于描述业务属性
    • 领域事件 (Domain Events):记录领域中发生的重要事情,用于跨聚合 / 跨上下文解耦通知(如订单创建后触发库存扣减事件)
    • 限界上下文 (Bounded Context):划分业务边界,为一个特定业务域建立独立的模型与语言空间;上下文之间通过上下文映射(如防腐层)交互,避免模型混乱
  • 特点:
    • 富血模型:业务逻辑封装在领域对象内部(实体 / 值对象 / 领域服务),而非贫血的 “数据类 + 服务” 模式
    • 通用语言 (Ubiquitous Language):代码中的类名、方法名、术语与业务专家、业务文档保持一致,实现 “业务即代码,代码即文档”
  • 优点:
    • 完美映射复杂业务场景,业务规则清晰可追溯
    • 高内聚、低耦合,业务边界明确,利于系统演进
    • 便于业务人员理解代码,减少沟通壁垒
  • 缺点:
    • 对团队建模能力和业务理解要求高,学习曲线陡峭
    • 开发成本较高(前期设计、沟通、评审成本增加)
    • 对简单 CRUD 系统过度设计,性价比低
  • 适用场景:
    • 业务逻辑极其复杂、规则多变的核心系统(如金融交易、电商核心、物流调度、医疗业务)
    • 需要长期演进、业务持续迭代的中大型系统
    • 团队具备资深架构师、领域专家,且能投入足够时间进行领域建模

4.命令查询职责分离(CQRS)
CQRS通常不是一种独立的顶层架构,而是一套用于优化数据访问和状态管理的高级设计模式,旨在将一个系统的读操作(查询)和写操作(命令)分离开来。常与 DDD (领域驱动设计) 和 整洁架构 结合使用,以构建高并发、可追溯的复杂系统。
6bac6d53-1489-48f1-99f9-e8c395e5bfbe

  • 其核心概念:
    • 分离读写模型: 将数据的写操作 (命令 Command) 与 读操作 (查询 Query) 完全分离
    • 查询(Query): 负责获取数据。它无副作用,直接返回用于展示的 DTO (Data Transfer Object),通常不经过复杂的领域逻辑
    • 独立存储: 写模型和读模型可以是完全不同的数据结构,甚至存储在不同的数据库中(例如:写操作使用关系型数据库保证强一致性,读操作使用 Redis/Elasticsearch 保证高性能)
    • 事件追溯(Event Sourcing, ES): 状态 = 事件流,不存储实体的当前状态,而是存储实体在生命周期内发生的所有事件。系统的当前状态是通过重放所有事件计算得出的。可追溯性,完整的事件日志提供了不可篡改的审计日志,支持历史回溯、版本管理和复杂的业务分析
  • 特点:
    • 读写性能独立优化: 读多写少场景下,可针对读模型进行大规模缓存、索引优化;写模型则专注于业务逻辑和数据一致性
    • 与 MediatR 结合: 在 .NET 生态中,常使用 MediatR 库来实现命令和查询的处理管道(Pipeline),提供优雅的消息分发和中间件扩展(如验证、日志、事务)
    • 事件驱动: 整个系统以事件为核心,命令触发事件,事件更新状态,形成事件驱动架构
  • 优点:
    • 高性能: 读写分离,读模型可灵活使用缓存、搜索引擎,极大提升查询性能
    • 高安全: 命令侧可进行严格的业务验证和权限控制,查询侧无状态且无副作用,降低风险
    • 高可扩展: 读写模型可独立水平扩展,系统弹性更好
    • 可追溯: 事件溯源提供了完整的数据变更历史,满足审计、合规和复杂业务分析需求
  • 缺点:
    • 复杂性剧增: 需要维护两套模型(读写),代码量和开发复杂度显著提升
    • 最终一致性: 读写模型之间通常是最终一致性,可能存在短暂的延迟,需要处理并发和数据同步问题
    • 调试困难: 数据流向从 “直接读写” 变为 “命令→事件→投影”,逻辑链条变长,调试和问题定位难度增加
    • 学习曲线陡峭: 对开发者的事件驱动、领域建模能力要求很高
  • 适用场景:
    • 高并发系统: 如秒杀系统、社交平台feed流,读请求远多于写请求
    • 复杂业务领域: 与DDD结合,用于处理复杂的业务逻辑和状态流转
    • 需要审计与追溯: 如金融交易系统、医疗记录系统,必须保留完整操作历史
    • 报表系统: 读模型可预生成为专门的报表结构,提升报表生成效率

5.微服务架构(Microservices)
微服务架构是一种分布式系统架构风格.NET Core/.NET 6+凭借跨平台、轻量化、高性能的特性,成为微服务开发的主流技术栈。
fc1a8856-06ed-46b7-8f1a-e48c39391cb4

  • 其核心概念:
    • 把单体应用拆分成多个小型、自治、独立部署的服务
    • 每个服务专注单一业务领域(遵循单一职责原则)
    • 服务独立数据库(Database per Service),不共享数据库
    • 统一入口通过 API 网关 提供,服务间使用 HTTP /gRPC/ 消息队列通信
  • 特点:
    • 去中心化:服务可独立选择技术栈、数据库、架构模式
    • 独立部署:单个服务更新、扩容、重启不影响其他服务
    • 容错性强:单个服务故障不会导致整体系统崩溃(需配合熔断、限流、降级)
  • 优点:
    • 支持无限水平扩展,可对高负载模块独立扩容
    • 团队自治,符合康威定律,适合大型团队并行开发
    • 技术选型灵活,不同服务可使用最适合的技术方案
    • 系统可维护性、可演进性更强
  • 缺点:
    • 分布式系统固有复杂性:网络延迟、分布式事务、服务治理、链路追踪等难度提升
    • 运维成本高:必须依赖 Docker、K8s、DevOps 体系
    • 数据一致性难以保证:需要使用 Saga、TCC、本地消息表等最终一致性方案
    • 调试与测试更复杂
  • 适用场景:
    • 大型 / 超大型互联网系统,单体架构已无法支撑扩展
    • 多团队协作、需要并行开发、独立发布的企业级系统
    • 部分模块需要独立弹性伸缩(如秒杀、支付、搜索、报表)
    • 长期迭代、业务边界清晰的复杂系统

至于MVC架构
Model:整个业务领域(包含数据 + 核心业务逻辑 + 规则),View:所有用户界面,Controller:所有输入处理逻辑
在现代BS架构中很少再把它看做一个单独的架构去使用,而是更多的把他作为“表现层模式”去使用,比如在上诉提到的三层架构中MVC退化为专门解决HTTP请求如何处理HTML如何渲染的模式;故没有单独拎出来作为一个设计架构来展开说明。
资料来源:
微软
架构师蓝图
Edison Zhou

posted @ 2026-03-26 15:40  Random吨  阅读(7)  评论(0)    收藏  举报