Skip to content

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 直接传进内圈)
java
// ✅ 正确:内圈(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 可以看作"六边形/洋葱思想的完整落地规范"——它把"依赖倒置"具体成了四层 + 一条铁律。

Clean Architecture 四层同心圆:依赖只能从外指向内,内圈不依赖外圈

五、落地(Spring 里怎么组织)

java
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 项目,把四层结构和依赖规则真正跑起来。