分层架构图解
本文档引用的文件
- MyEntityNameController.cs
- IMyEntityNameAppService.cs
- MyEntityNameAppService.cs
- MyEntityName.cs
- IMyEntityNameRepository.cs
- EfCoreMyEntityNameRepository.cs
- CMSPluginDomainModule.cs
- CMSPluginEntityFrameworkCoreModule.cs
- CMSPluginModule.cs
目录
引言
本文档旨在全面解析项目的分层架构设计,涵盖表现层(Controller)、应用层(Application Service)、领域层(Domain Model)和基础设施层(EntityFrameworkCore Repository)。通过代码分析和图解方式,展示从HTTP请求进入系统到数据持久化的完整链路,阐明各层职责、依赖方向和设计原则。
分层架构概览
本项目采用典型的领域驱动设计(DDD)分层架构,分为四层:
- 表现层:位于
Controller目录,处理HTTP请求和响应 - 应用层:位于
Application和Application.Contracts目录,编排业务用例 - 领域层:位于
Domain目录,承载核心业务逻辑和规则 - 基础设施层:位于
EntityFrameworkCore目录,实现数据访问和持久化
这种分层架构遵循依赖倒置原则,高层模块不依赖于低层模块,两者都依赖于抽象。
图解来源
- MyEntityNameController.cs
- IMyEntityNameAppService.cs
- MyEntityNameAppService.cs
- MyEntityName.cs
- IMyEntityNameRepository.cs
各层职责划分
表现层(Controller)
表现层的职责严格限定为:
- 接收HTTP请求并进行路由
- 验证请求参数的基本格式
- 调用应用服务接口
- 封装并返回HTTP响应
在MyEntityNameController中,所有方法都只是简单地委托给IMyEntityNameAppService接口,不包含任何业务逻辑。
本节来源
应用层(Application Service)
应用层负责:
- 编排业务用例的执行流程
- 协调多个领域对象的交互
- 处理事务边界
- 进行应用级别的验证
- 实现DTO与领域模型之间的转换
MyEntityNameAppService实现了IMyEntityNameAppService接口,协调领域模型和仓储之间的交互。
本节来源
领域层(Domain Model)
领域层是业务核心,职责包括:
- 定义实体、值对象和聚合根
- 封装核心业务规则和不变性
- 实现领域行为而非仅是数据容器
- 确保业务状态的一致性
MyEntityName类不仅包含属性,还定义了Update、AdjustSort和Clone等业务行为方法。
本节来源
基础设施层(Repository)
基础设施层的职责是:
- 抽象数据访问细节
- 提供领域层所需的查询 和持久化能力
- 实现仓储接口的具体技术方案
- 处理数据库连接、事务等技术细节
EfCoreMyEntityNameRepository实现了IMyEntityNameRepository接口,使用Entity Framework Core进行数据访问。
本节来源
数据调用流程图解
以下序列图展示了从HTTP请求到数据库持久化的完整调用链路:
图解来源
- MyEntityNameController.cs
- MyEntityNameAppService.cs
- MyEntityName.cs
- IMyEntityNameRepository.cs
- EfCoreMyEntityNameRepository.cs
依赖关系与接口设计
本架构严格遵循依赖倒置原则(DIP),各层之间的依赖关系如下:
图解来源
- MyEntityNameController.cs
- IMyEntityNameAppService.cs
- MyEntityNameAppService.cs
- IMyEntityNameRepository.cs
- EfCoreMyEntityNameRepository.cs
- MyEntityName.cs
依赖倒置原则的实际体现
- 表现层依赖应用层接口:
MyEntityNameController依赖IMyEntityNameAppService接口而非具体实现 - 应用层依赖领域层接口:
MyEntityNameAppService依赖IMyEntityNameRepository接口而非EfCoreMyEntityNameRepository具体类 - 基础设施层实现领域层接口:
EfCoreMyEntityNameRepository实现IMyEntityNameRepository接口
这种设 计使得各层可以独立开发、测试和替换,例如可以轻松更换数据访问技术而不影响业务逻辑。
本节来源
依赖注入与松耦合实现
项目通过依赖注入容器实现松耦合,各层的依赖关系在运行时由容器解析:
图解来源
为何Application层依赖Domain而非反之
- 业务逻辑稳定性:领域层包含核心业务规则,相对稳定;应用层处理用例编排,可能频繁变 化
- 抽象层次:领域层代表业务概念,是更高层次的抽象;应用层是业务概念的具体应用
- 重用性:领域模型可以在多个应用服务中重用,而应用服务通常是特定用例的
- 测试隔离:领域层可以独立于应用层进行单元测试,确保核心业务逻辑的正确性
本节来源
典型调用栈示例
以下是一个创建MyEntityName实体的典型调用栈:
1. MyEntityNameController.CreateAsync(input)
↓ 调用应用服务接口
2. MyEntityNameAppService.CreateAsync(input)
↓ 检查名称是否存在
3. IMyEntityNameRepository.NameExistAsync(input.Name)
↓ EF Core实现
4. EfCoreMyEntityNameRepository.NameExistAsync(name)
↓ 数据库查询
5. Database: SELECT COUNT(*) FROM myentitynames WHERE name = @name
↓ 返回结果
6. EfCoreMyEntityNameRepository 返回 bool
↓ 返回结果
7. MyEntityNameAppService 接收结果
↓ 检查业务规则
8. MyEntityNameAppService.GetMaxSortAsync()
↓ 获取最大排序值
9. EfCoreMyEntityNameRepository.GetMaxSortAsync()
↓ 数据库查询
10. Database: SELECT MAX(sort) FROM myentitynames
↓ 创建领域对象
11. new MyEntityName(id, code, name, sort, remark)
↓ 持久化实体
12. IMyEntityNameRepository.InsertAsync(myEntityName)
↓ EF Core插入
13. EfCoreMyEntityNameRepository.InsertAsync(entity)
↓ 数据库操作
14. Database: INSERT INTO myentitynames VALUES (...)
↓ 返回结果
15. EfCoreMyEntityNameRepository 返回 MyEntityName
↓ 转换为DTO
16. ObjectMapper.Map<MyEntityName, MyEntityNameDto>
↓ 返回结果
17. MyEntityNameAppService 返回 MyEntityNameDto
↓ 返回响应
18. MyEntityNameController 返回 201 Created
本节来源
常见架构误用及危害
在Controller中直接访问Repository
// 错误做法
[HttpPost]
public async Task<MyEntityNameDto> CreateAsync(MyEntityNameCreateDto input)
{
// 直接访问Repository,违反分层原则
var exist = await _myEntityNameRepository.NameExistAsync(input.Name);
if (exist)
{
throw new UserFriendlyException("名称已存在");
}
var myEntityName = new MyEntityName(Guid.NewGuid(), input.Code, input.Name);
await _myEntityNameRepository.InsertAsync(myEntityName);
return ObjectMapper.Map<MyEntityName, MyEntityNameDto>(myEntityName);
}
危害:
- 破坏分层:表现层直接依赖基础设施层,破坏了架构的清晰边界
- 重复代码:业务规则(如名称唯一性检查)在多个Controller中重复
- 难以测试:Controller变得臃肿,难以进行单元测试
- 耦合度高:Controller与数据访问技术耦合,难以更换数据库技术
- 事务管理困难:复杂的业务操作难以保证事务一致性
正确做法:所有业务逻辑都应在应用层处理,Controller只负责请求路由和响应封装。
本节来源
结论
本项目的分层架构设计遵循领域驱动设计原则,通过清晰的职责划分和依赖倒置实现了高内聚、低耦合的系统结构。表现层专注于请求响应处理,应用层编排业务用例,领域层承载核心业务规则,基础设施层抽象数据访问。各层通过接口进行通信,依赖注入容器负责实例化和依赖解析,确保了系统的可维护性、可测试性和可扩展性。遵循此架构模式,可以有效避免常见的架构误用,构建健壮的企业级应用系统。