Post
清洁架构:分层设计如何实现业务与技术的解耦
概述
清洁架构(Clean Architecture)是一种以业务逻辑为核心、强调解耦与可维护性的软件架构模式。其核心目标是实现业务规则与技术实现的分离,确保系统在面对框架变更、UI调整或第三方依赖更新时保持稳定性。
核心概念
清洁架构通过分层结构和依赖反转实现系统解耦:
- 实体层(Entities):包含领域模型和业务规则,是纯粹的业务逻辑核心
- 用例层(Use Cases):定义应用的具体业务流程,通过调用实体完成任务
- 接口适配层(Interface Adapters):负责数据格式转换,如HTTP控制器、gRPC服务等
- 框架驱动层(Frameworks & Drivers):包含技术实现细节,如Web框架、数据库、UI组件
这种设计遵循依赖倒置原则:外层(技术实现)可以依赖内层(业务逻辑),但内层不能依赖外层。通过接口抽象实现双向隔离。
工作原理
清洁架构的分层机制通过以下方式实现解耦:
- 单向依赖:依赖方向从外层指向内层,避免技术细节污染业务逻辑
- 接口隔离:各层通过定义良好的接口通信,降低耦合度
- 可测试性:业务逻辑层独立于具体实现,便于单元测试和模拟
例如,在HTTP服务中,Web层(接口适配器)通过接口调用用例层,而用例层仅依赖实体层的接口,不直接访问数据库或框架。
使用方法
项目结构设计
典型项目结构遵循以下分层规范:
application/
├── cmd/ # 入口程序
├── internal/
│ ├── domain/ # 实体层(Entities)
│ ├── usecase/ # 用例层(Use Cases)
│ ├── adapter/ # 接口适配层(HTTP/gRPC)
│ └── layer/ # 基础设施层(数据库/日志)
└── pkg/ # 工具函数库
命名规范建议
| 原目录名 | 问题 | 推荐名称 | 原因说明 |
|---|---|---|---|
| delivery/http | 冲突标准库 net/http |
delivery/web 或 handler | 避免命名冲突,提升可读性 |
| repository | 无问题 | repo/postgres | 明确技术实现细节 |
| usecase | 无问题 | 保持原名 | 符合领域驱动设计惯例 |
示例
以用户管理模块为例:
- 实体层定义
User模型和验证规则 - 用例层实现
CreateUser业务逻辑 - 接口适配层通过HTTP接口接收请求,调用用例层
- 基础设施层实现数据库存储(如PostgreSQL)
1// 实体层(domain/user.go)
2type User struct {
3 ID string
4 Name string
5 Email string
6}
7
8// 用例层(usecase/user.go)
9func CreateUser(name, email string) (*User, error) {
10 // 调用实体层验证规则
11 if !isValidEmail(email) {
12 return nil, errors.New("invalid email")
13 }
14 return &User{ID: generateID(), Name: name, Email: email}, nil
15}
16
17// 接口适配层(adapter/web/user_handler.go)
18func CreateUserHandler(w http.ResponseWriter, r *http.Request) {
19 // 调用用例层
20 user, err := usecase.CreateUser("John", "john@example.com")
21 if err != nil {
22 http.Error(w, err.Error(), http.StatusBadRequest)
23 return
24 }
25 // 返回响应
26 json.NewEncoder(w).Encode(user)
27}
常见问题
- 命名冲突:避免使用
http等标准库同名目录,建议改用web或handler - 依赖管理:确保基础设施层不直接引用业务逻辑层代码
- 测试隔离:通过接口模拟基础设施层,实现纯粹的单元测试
总结
清洁架构通过分层设计和依赖反转,实现了业务逻辑与技术实现的解耦。这种架构模式特别适合需要长期维护、频繁迭代的系统,能有效降低技术债务,提升代码可测试性和可扩展性。实际应用中需注意命名规范和依赖边界,避免因技术细节污染核心业务逻辑。