三层模式(真实项目的干净架构)

在构建可扩展的后端系统(API、机器人、Web 应用程序)时,我们将职责分层。

为什么?

因为将所有内容混合在一个文件中会导致:

  • 意大利面条代码
  • 硬调试
  • 硬测试
  • 硬缩放
  • 客户改变需求时的痛苦

所以我们使用:


什么是三层模式?

它是一种代码组织结构,将应用程序分为三个逻辑层:

1.处理层(表示层)
2.服务层(业务逻辑层)
3. 存储库层(数据层)

每一层都只有一个职责

简单的想法。强大的影响力。


为什么需要它?

想象一下您的 OMR Streamlit 应用程序。

如果您:

  • 检测图像
  • 分析答案
  • 转换为 JSON
  • 存储在 MongoDB 中
  • 返回响应

全部都在一个函数内……

现在客户说:

“存储在 PostgreSQL 而不是 Mongo 中。”

现在你必须修改一切😵

但如果你使用图层:

  • 仅存储库层发生变化。
  • 应用程序的其余部分保持不变。

这就是清洁工程。


它解决了什么问题?

无层 分层
乱码 清洁分离
调试困难 轻松调试
难以测试 简单的单元测试
紧耦合 松耦合
改变打破一切 更改仅影响一层

该模式解决了:

  • 可维护性问题
  • 可扩展性问题
  • 测试问题
  • 代码可读性问题

第 1 层:处理程序(看门人🚪)

这是什么?

Handler 是应用程序的入口点。

它讲述的是:

  • HTTP 请求
  • 流线型用户界面
  • 电报消息
  • REST API 调用

它理解:

  • JSON
  • HTTP
  • 状态代码
  • 用户输入

它到底有什么作用?

它:

  • 解析 JSON → 转换为 Python 字典
  • 验证输入
  • 调用服务层
  • 返回 HTTP 响应

它不:

  • 直接与数据库对话
  • 包含业务逻辑
  • 执行繁重的计算

示例(登录 API)

1
2
3
4
5
6
7
8
9
10
@app.post("/login")
def login_handler(request):
data = request.json()

if "email" not in data:
return {"error": "Email required"}, 400

result = auth_service.login(data["email"], data["password"])

return result, 200

第一层:服务(应用程序的大脑)

什么是服务层?

服务层是应用程序的一部分,包含核心业务逻辑

它负责:

  • 做出决定
  • 应用业务规则
  • 协调工作流程
  • 调用存储库
  • 调用外部服务(电子邮件、付款等)

它不处理:

  • HTTP
  • JSON解析
  • 状态代码
  • 用户界面渲染

服务层只关注系统应该做什么,而不关注请求如何到达。


为什么需要服务层?

没有服务层:

  • 业务逻辑在控制器内部混合。
  • 代码变得混乱且紧密耦合。
  • 测试变得困难。
  • 逻辑不能在不同环境中重用。

服务层确保:

  • 干净的架构
  • 可重复使用性
  • 可维护性
  • 可扩展性
  • 简单的单元测试

它解决了什么问题?

Service层解决:

1️⃣ 关注点分离

将业务逻辑与 HTTP 或 UI 逻辑分开。

2️⃣ 可重复使用性

以下人员可以使用相同的服务:

  • 休息API
  • 电报机器人
  • CLI 脚本
  • 后台工作者
  • 计划任务

3️⃣ 可测试性

您可以在不运行 Web 服务器的情况下测试业务逻辑。

4️⃣ 可维护性

如果业务规则发生变化,只需要修改服务层。


🔄 工作原理(流程示例)

示例:课程购买系统

客户发送购买课程的请求。

步骤 1️⃣ 控制器接收请求

  • 解析 JSON
  • 验证输入
  • 调用服务层
1
purchase_service.buy_course(user_id, course_id, payment_token)

第 3 层:存储库层(数据访问层)

什么是存储库层?

存储库层 负责处理与数据库的所有交互。

该层:

  • 执行 SQL/NoSQL 查询
  • 从数据库中获取数据
  • 插入新记录
  • 更新现有记录
  • 删除记录
  • 将数据库行/文档映射到应用程序对象

它充当应用程序和数据库之间的桥梁

存储库不包含业务逻辑。
它只处理数据持久性。


为什么需要存储层?

没有存储库层:

  • 数据库查询分散在控制器和服务中。
  • 代码与特定数据库紧密耦合。
  • 更改数据库变得很痛苦。
  • 测试变得困难。

存储库层确保:

  • 清晰的关注点分离
  • 数据库抽象
  • 更轻松的数据库切换
  • 更好的可维护性
  • 测试中更容易模拟

它解决了什么问题?

1️⃣ 防止控制器中的数据库逻辑

控制器不应编写 SQL 查询。

2️⃣ 防止服务中的数据库逻辑

服务应该关注业务规则,而不是 SQL 语法。

3️⃣ 减少紧耦合

如果明天你从 MongoDB 切换到 PostgreSQL,
仅存储库发生变化。

4️⃣ 提高可测试性

您可以在测试期间模拟存储库方法,而无需真正的数据库。


存储库到底有什么作用?

存储库:

  • 运行数据库查询
  • 将原始数据库数据转换为可用对象
  • 处理低级数据访问逻辑
  • 将干净的数据返回给服务层

它不:

  • 应用业务规则
  • 处理HTTP
  • 验证请求输入
  • 格式化 API 响应

工作原理(流程示例)

示例:用户登录系统

步骤 1️⃣ 控制器接收请求

  • 解析 JSON
  • 通话服务
1
auth_service.login(email, password)