4、分层架构核心理论:经典三层架构详解
说到分层架构,很多人第一反应就是「三层架构」。没错,它确实是软件工程里最经典、最基础的分层模式。我做了十几年系统设计,见过无数项目从单体直接拆成微服务,结果拆得七零八落。其实很多场景下,老老实实把三层架构做好,比盲目追新要靠谱得多。
今天我们就来把三层架构彻底聊透。我会结合自己踩过的坑,帮你理解每一层到底该干什么、不该干什么,以及层与层之间怎么通信才不「越界」。
4.1 三层架构的由来与本质
三层架构不是谁拍脑袋想出来的。它源于一个很朴素的诉求:让代码各司其职。
早期开发经常是 JSP 里写 SQL,HTML 里混业务逻辑。改一个需求,要翻遍所有文件。后来大家发现,如果把界面、业务、数据这三件事分开,维护成本会大幅下降。这就是三层架构的初衷。
三层架构的典型结构是这样的:
- 表现层(Presentation Layer):负责与用户交互,展示数据、接收输入。
- 业务层(Business Layer):负责核心业务逻辑、规则校验、流程编排。
- 数据层(Data Layer):负责数据持久化、访问数据库或外部存储。
你想想看,这三层就像一家公司的三个部门:前台接待(表现层)、业务经理(业务层)、仓库管理员(数据层)。前台不能直接去仓库搬货,业务经理也不能自己去前台站岗。各司其职,才能高效运转。
4.2 各层职责详解
4.2.1 表现层:只做「翻译」和「传递」
表现层的职责其实很单纯:把用户的操作翻译成业务层能理解的请求,再把业务层返回的结果翻译成用户能看懂的界面。
我在项目中遇到过不少团队,喜欢在表现层写业务逻辑。比如在 Controller 里直接做金额计算、状态判断。嗯,这里要提醒你:表现层一旦开始「思考」,代码就离失控不远了。
表现层应该包含的内容:
- 视图渲染(HTML、JSON、XML 等)
- 输入校验(格式校验,如邮箱格式、必填项)
- 会话管理(登录状态、Token 校验)
- 异常处理(统一错误页面或错误码返回)
表现层不应该包含的内容:
- 业务规则判断(如「用户余额是否足够」)
- 数据访问逻辑(如直接写 SQL)
- 复杂的状态转换
4.2.2 业务层:系统的「大脑」
业务层是整个架构的核心。说白了,业务层就是把你脑子里的业务规则翻译成代码。
我个人习惯把业务层分成两部分:
- 业务逻辑:核心算法、规则引擎、状态机
- 业务编排:调用多个数据层方法,组合成完整的业务流程
举个例子,下单流程:
- 校验库存(调用数据层)
- 扣减库存(调用数据层)
- 生成订单(调用数据层)
- 发送通知(调用外部服务)
这些步骤的编排,就是业务层的职责。表现层只需要说「用户要下单」,剩下的全交给业务层。
4.2.3 数据层:只做「存取」
数据层的职责非常明确:封装对数据源的访问,提供 CRUD 操作。
数据层不应该包含任何业务逻辑。比如「查询用户订单」和「查询用户订单并计算总价」——前者是数据层的事,后者是业务层的事。
数据层的典型实现:
- DAO(Data Access Object)模式
- Repository 模式
- ORM 框架(MyBatis、Hibernate、Entity Framework)
| 层 | 核心职责 | 常见错误 |
|---|---|---|
| 表现层 | 用户交互、数据展示、输入校验 | 写业务逻辑、直接访问数据库 |
| 业务层 | 业务规则、流程编排、事务管理 | 过度膨胀、与表现层耦合 |
| 数据层 | 数据存取、ORM 映射、连接管理 | 包含业务判断、暴露内部实现 |
4.3 层间通信规则
三层架构的通信规则其实就一句话:上层依赖下层,下层不依赖上层。
具体来说:
- 表现层调用业务层
- 业务层调用数据层
- 数据层不反向调用
为什么这么设计?因为一旦下层依赖上层,就会出现循环依赖。你想想看,如果数据层调用了业务层,那业务层又调用了数据层,代码就成了一团乱麻。
3.1 通信方式
层间通信通常有两种方式:
- 接口调用:上层通过接口调用下层的方法。这是最常用的方式。
- 事件驱动:上层发布事件,下层订阅事件。这种方式适合解耦,但会增加复杂度。
我个人更推荐接口调用。原因很简单:简单、直观、容易调试。事件驱动虽然时髦,但如果你不是处理异步场景,没必要给自己找麻烦。
3.2 数据传输对象(DTO)
层间通信时,数据怎么传?我的建议是:使用 DTO(Data Transfer Object)。
举个例子:
// 表现层接收的请求
public class CreateOrderRequest {
private String userId;
private List<OrderItemDTO> items;
// getter/setter
}
// 业务层返回的结果
public class OrderResult {
private String orderId;
private BigDecimal totalAmount;
private String status;
// getter/setter
}
为什么不用实体类直接传?因为实体类通常包含数据库字段、关联关系等内部细节。暴露给表现层,等于把家底都亮出来了。DTO 可以只包含需要的字段,既安全又清晰。
4.4 三层架构的变体与扩展
实际项目中,三层架构往往会有一些变体:
- 四层架构:在业务层和数据层之间加一层「服务层」,用于处理跨业务模块的调用。
- 领域驱动设计(DDD):把业务层拆得更细,引入领域模型、聚合、值对象等概念。
- 微服务架构:每个微服务内部仍然是三层架构,只是服务之间通过 RPC 或消息队列通信。
但不管怎么变,核心思想不变:分层是为了解耦,解耦是为了可维护。
4.5 本章小结
三层架构不是什么高深的理论,但它是最实用的架构模式之一。我做了这么多年,见过太多项目因为分层不清晰而陷入混乱。记住三点:
- 各层职责要清晰:表现层只做界面,业务层只做逻辑,数据层只做存取。
- 通信规则要遵守:上层依赖下层,不反向调用,不越层调用。
- 数据传输要规范:使用 DTO,不暴露内部实现。
把这些基础打牢了,后面学更复杂的架构模式才会得心应手。