Clean Architecture(整洁架构)是 Robert Martin(《代码整洁之道》作者)提出的,是《六边形与洋葱架构》的"系统化版本"。核心就一条依赖规则,但这条规则价值极高,面试也高频。这篇把它讲透:四层同心圆各是什么、依赖规则怎么落地。
一、解决什么问题
和六边形/洋葱一样,Clean Architecture 解决的是"业务被开发框架绑架"的问题——业务代码里到处是 Spring 注解、MyBatis/JPA、数据库访问,换框架、换数据库都要动业务。但 Robert Martin 把它提炼成了更明确、更严格的一套规则——四层同心圆 + 依赖规则。
二、四层同心圆
从内到外四层,越往里越核心、越稳定:
① Entities(实体) —— 企业级业务规则(最核心、最稳定)
② Use Cases(用例) —— 应用级业务规则(业务流程编排)
③ Interface Adapters(接口适配器)—— Controller、Presenter、Repository 接口
④ Frameworks & Drivers(框架和驱动)—— Spring、数据库、Web 框架(最外层)| 层 | 是什么 | 例子 | 变化频率 |
|---|---|---|---|
| Entities | 业务实体 + 企业规则 | Order 实体、金额计算规则 | 几乎不变 |
| Use Cases | 应用用例(业务流程) | 下单用例、支付用例 | 业务变化时变 |
| Interface Adapters | 数据格式转换、接口定义 | Controller、Repository 接口 | 技术变化时变 |
| Frameworks | 具体框架和工具 | Spring、MySQL、Vue | 频繁变 |
三、核心:依赖规则(Dependency Rule)
Clean Architecture 的灵魂是一条规则:
依赖只能从外圈指向内圈。内圈绝对不依赖外圈。
翻译成人话:
- 外圈(框架/数据库)可以依赖内圈(业务),内圈绝不依赖外圈
- 内圈的代码里不能出现 Spring 注解、数据库类、框架类——内圈是纯业务代码
- 数据从外圈流向内圈时,要转换成内圈认识的对象(不能把外圈的 DTO 直接传进内圈)
// ✅ 正确:内圈(Use Case)依赖 Entities,不依赖框架
public class PlaceOrderUseCase {
private final OrderRepository repository; // 依赖接口(内圈定义的)
public void execute(PlaceOrderCommand cmd) {
Order order = Order.create(cmd.getCustomerId(), cmd.getAmount());
repository.save(order); // 依赖接口,不是 MySQL 实现
}
}
// ✅ 外圈(框架)实现内圈定义的接口
@Repository // 注解只出现在外圈
public class MySqlOrderRepository implements OrderRepository { ... }注意:@Repository 这种 Spring 注解只出现在最外圈,内圈的 PlaceOrderUseCase 是纯 Java,不 import 任何框架类。
四、和六边形/洋葱的关系
三者是同一个思想的不同表述:
| 架构 | 特点 |
|---|---|
| 六边形 | 端口 + 适配器,强调"外部通过端口接入" |
| 洋葱 | 同心圆,把业务核心再分层 |
| Clean Architecture | 系统化:明确四层 + 依赖规则,最严格最完整 |
Clean Architecture 可以看作"六边形/洋葱思想的完整落地规范"——它把"依赖倒置"具体成了四层 + 一条铁律。
五、落地(Spring 里怎么组织)
com.demo.order
├── entity // ① Entities:纯业务对象
│ └── Order.java
├── usecase // ② Use Cases:业务流程
│ ├── PlaceOrderUseCase.java // 依赖 entity + 接口
│ └── OrderRepository.java // 接口(内圈定义的端口)
├── adapter // ③ Interface Adapters:数据转换 + 接口实现
│ ├── OrderController.java // 接收 HTTP,转成 Use Case 的命令对象
│ └── MySqlOrderRepository.java // 实现内圈的接口
└── framework // ④ Frameworks:Spring 配置、数据库连接
└── AppConfig.java判定的口诀:如果一个类的 import 里出现了 @Controller、@Service、@Mapper、Spring、MyBatis 这些——它一定在最外圈。内圈的类 import 只有 java.* 和自己项目的 entity/usecase。
六、代价与取舍
Clean Architecture 不是免费的:
- 样板代码多:每层要转换对象(DTO → Command → Entity),层与层之间的转换器写一堆
- 上手慢:团队要理解"依赖规则",否则会不自觉地在内圈 import 框架类
所以和 DDD 一样——复杂、需要长期演进、业务规则重的系统才值得用。简单 CRUD 用分层架构就够了,硬上 Clean Architecture 是过度设计。
小结
- Clean Architecture 是"业务核心独立 + 依赖倒置"的系统化版本
- 四层同心圆:Entities → Use Cases → Interface Adapters → Frameworks
- 核心依赖规则:依赖只能外指向内,内圈不依赖框架和数据库
- 和六边形/洋葱同源,是最严格最完整的表述
- 复杂业务才用,简单 CRUD 别硬套
这条"分层架构演进"线到这里就闭环了:分层架构(业务依赖数据库)→ 六边形/洋葱(依赖倒置)→ Clean Architecture(系统化的依赖规则)。想了解这条线怎么在复杂业务里落地,可以回头看《DDD 领域驱动设计》——DDD 的领域层就是这些架构里那个"内圈"。
想在真实项目里看 Clean Architecture 怎么落地,看我在 NestJS 里的实践系列《Clean Architecture在NestJS中的实践(一):项目初始化》——从零搭建一个 CA 项目,把四层结构和依赖规则真正跑起来。
