后端三层架构
架构
依赖倒置原则:高层模块不应该依赖低层模块,二者都应依赖抽象接口;抽象接口不应该依赖实现,而实现应依赖抽象接口。
架构到底是什么我现在也没太弄清楚,不过按照我目前的认知,架构大体上可以看作是依赖倒置原则在系统层面的体现,从抽象的角度去规范各个部分之间的连接关系和协作边界。比如对于一个后端服务,从接收前端请求到执行业务逻辑再到数据存储,可以把整个流程大致拆分成三层:表现层、业务层、数据层。
表现层
控制器接口
Flask 路由函数
解耦 UI 与服务调用
业务层
服务接口(如 IUserService
)
实际服务实现
解耦流程逻辑与实现细节
数据层
数据访问接口(DAO)
SQLAlchemy / ORM
解耦业务逻辑与存储实现
每一层都可能包含多个模块以实现不同的功能,不过在确定了采用三层架构之后,实现代码的时候就能明确地知道每个功能属于哪一层以及应该怎么被调用,开发一个更大的功能时候也可以合理地进行任务拆分。一旦这套抽象的结构清晰了,哪怕系统变得越来越大,也不容易变得混乱。比如采用三层架构之后,在写 Flask 路由函数的时候就能明确它属于表现层,只负责接收请求和参数校验,不能写业务逻辑、也不能直接操作数据库。它只能调用业务层暴露出来的接口,后者再去处理复杂的逻辑和数据。这样整个项目就很干净、耦合度比较低。
后端三层架构
1 2 3 🔁 请求 -> 表现层(路由函数) ↳ 业务层(服务逻辑处理) ↳ 数据层(持久化)
1. 表现层(Presentation Layer)
表现层用于接收 HTTP 请求(URL、Body、Header)、参数校验(通常使用 Pydantic)、调用业务逻辑(Service 层)、返回标准响应(JSON)。这里不应该写业务逻辑(比如“用户名是否重复”),也不应直接操作数据库。职责就是请求转发器 + 校验网关。
1 2 3 4 5 6 @app.route("/users" , methods=["POST" ] ) def create_user (): data = request.json user_data = UserCreate(**data) user = UserService.create_user(user_data) return jsonify(user.model_dump()), 201
2. 业务层(Business Layer / Service)
业务层负责编排流程、控制事务边界,校验权限、状态(如“是否已存在”),调用 DAO 或外部服务(邮件、缓存、日志等),这一层实际执行业务流程。
1 2 3 4 5 6 7 class UserService : @staticmethod def create_user (user_data: UserCreate ) -> UserOut: if DBUserDAO.get_by_username(user_data.username): raise ValueError("用户名已存在" ) user = DBUserDAO.create(user_data.model_dump()) return UserOut.model_validate(user)
3. 数据层(Data Layer / DAO)
数据层只负责与数据库、文件、缓存打交道,封装 SQLAlchemy 的查询、插入、删除等操作。这一层不能加任何业务判断,比如“用户名是否重复”这种逻辑必须上移。
1 2 3 4 class UserDAO : @staticmethod def get_user_by_username (session, username ): return session.query(User).filter_by(username=username).first()
常见工具与实践
Pydantic
Pydantic 是一个通过 Python 的类型注解来实现特定数据结构自动校验和转换的工具。比如以下是一个 Pydantic 的使用示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 from pydantic import BaseModel, Fieldfrom typing import Optional class User (BaseModel ): id : int = Field(..., gt=0 , description="用户ID,必须大于0" ) username: str = Field(..., min_length=3 , max_length=20 , description="用户名,长度3~20" ) email: Optional [str ] = Field(default=None , description="可选邮箱地址" ) age: int = Field(default=18 , ge=0 , le=150 , description="年龄,默认18,范围 0~150" ) model_config = { "from_attributes" : True } external_data = { "id" : "100" , "username" : "alice" , "email" : "alice@example.com" } user = User.model_validate(external_data) print ("✅ 构建后的模型对象:" )print (user)updated_user = user.copy(update={"age" : 25 }) print ("\n✅ 使用 .copy() 更新后的对象:" )print (updated_user)user_dict = updated_user.model_dump(exclude_none=True ) print ("\n✅ 导出为 dict(排除 None):" )print (user_dict)user_json = updated_user.model_dump_json(indent=2 ) print ("\n✅ 导出为 JSON:" )print (user_json)
Pydantic 通过使用 BaseModel
继承方式创建模型,通过类型注解确定各个参数的类型。其中,Field
部分并不是必须的,它是用于额外设置字段校验规则(如 gt=0
)和元信息(如 description
)。通过 model_validate
方法,可以从字典构建生成 Pydantic 对象。在对象生成的过程中,Pydantic 会自动地进行参数的检查和转换。通过 copy(update={})
的语法,可以修改 Pydantic 对象的值来生成一个新的对象。可以通过 model_dump
和 model_dump_json
方法来将 Pydantic 对象转换为字典和 JSON,在 Web 应用中非常方便。在三层架构中,表现层可以使用 Pydantic 校验请求参数,业务层可以使用 Pydantic 定义输入输出结构。
以一个用户创建的过程为例,我们首先定义 Pydantic 对象模型,该对象由前端发送过来的 JSON 创建,并作为业务逻辑层的参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from pydantic import BaseModel, EmailStr, Fieldclass UserCreate (BaseModel ): username: str = Field(..., min_length=3 ) email: EmailStr password: str = Field(..., min_length=6 ) class UserOut (BaseModel ): id : int username: str email: EmailStr model_config = { "from_attributes" : True }
定义一个创建用户的路由函数,通过 Pydantic 对象连接表现层和业务逻辑层:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from flask import request, jsonifyfrom schemas.user import UserCreatefrom services.user_service import UserService@app.route("/users" , methods=["POST" ] ) def create_user (): user_data = UserCreate.model_validate(request.json) result = UserService.create_user(user_data) return jsonify(result.model_dump()), 201
在业务逻辑层中,可以基于 Pydantic 对象的信息,执行调用 DAO 进行数据库写入等操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 from schemas.user import UserCreate, UserOutfrom dao.user_dao import UserDAOclass UserService : @staticmethod def create_user (user_data: UserCreate ) -> UserOut: user = UserDAO.create( username=user_data.username, email=user_data.email, password=user_data.password ) return UserOut.model_validate(user)
DAO:数据访问对象层
DAO(Data Access Object)负责把所有与存储逻辑相关的操作集中封装 起来。业务层不直接操作数据库,而是通过 DAO 来完成所有存储操作。这样可以让代码职责清晰、易于测试、易于扩展。数据存储的形式可能是文件系统、数据库、或者缓存,当需要使用不同的存储形式时,可以定义一个 DAO 抽象基类,各个存储形式具体实现该抽象基类的接口。这样可以使得业务层只依赖抽象,不关心底层用的是文件、数据库还是其他。如果调用方需要知道你是谁,那这个抽象就失败了。
我们可以定义一个类似于下方的 DAO,来封装与用户有关的数据库底层操作。这样像上方的 UserService 业务逻辑类,就只需要和 DAO 打交道,不需要实际处理数据库的连接写入等操作了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 from sqlalchemy.orm import Sessionfrom models.user import Userfrom utils.db import with_sessionfrom functools import wrapsfrom database import SessionLocaldef with_session (func ): @wraps(func ) def wrapper (*args, **kwargs ): session = SessionLocal() try : result = func(*args, session=session, **kwargs) session.commit() return result except Exception: session.rollback() raise finally : session.close() return wrapper class DBUserDAO : @staticmethod @with_session def get_by_id (user_id: int , session: Session ) -> User | None : return session.query(User).filter_by(id =user_id).first() @staticmethod @with_session def get_by_username (username: str , session: Session ) -> User | None : return session.query(User).filter_by(username=username).first() @staticmethod @with_session def create (user_data: dict , session: Session ) -> User: user = User(**user_data) session.add(user) session.flush() return user @staticmethod @with_session def delete (user_id: int , session: Session ) -> bool : session.query(User).filter_by(id =user_id).delete() return True
在 database.py 进行一些 SQLAlchemy 的连接配置:
1 2 3 4 5 6 7 8 9 10 11 12 from sqlalchemy import create_enginefrom sqlalchemy.orm import sessionmaker, declarative_baseDATABASE_URL = "sqlite:///./app.db" engine = create_engine( DATABASE_URL, connect_args={"check_same_thread" : False } if "sqlite" in DATABASE_URL else {} ) SessionLocal = sessionmaker(autocommit=False , autoflush=False , bind=engine) Base = declarative_base()
在 models/user.py 中定义 ORM 模型:
1 2 3 4 5 6 7 8 9 10 11 from sqlalchemy import Column, Integer, Stringfrom database import Baseclass User (Base ): __tablename__ = "users" id = Column(Integer, primary_key=True ) username = Column(String(50 ), unique=True , nullable=False ) email = Column(String(100 ), unique=True , nullable=False ) password = Column(String(100 ), nullable=False )
小结
架构类似于一种职责划分机制,它让系统中每一块代码都有清晰的定位,知道自己该做什么、不该做什么。在这篇文章中,我们把“架构”理解为一种更高层次的依赖倒置原则:上层不依赖下层的实现细节,而是依赖于稳定的抽象。架构的核心目标是解耦与稳定,只有当各部分之间建立在抽象接口上的协作关系时,系统才能在不断迭代中保持可维护性。三层架构通过将系统分为表现层、业务层、数据层,每一层各司其职,避免了逻辑混杂和功能重叠,使系统在结构上变得更加清晰、可控、可演进。三层架构在绝大多数中小型 Web 应用中都是非常适用的,比如它特别适合Web 服务型系统(如 Flask、Django、Spring Boot 等)或者API 驱动的接口后端(配合前端或移动端使用)。对于某些高性能系统、事件驱动架构、或者需要大量异步通信的微服务系统,三层架构可能会显得不够灵活,但掌握它是构建一个清晰、稳定、可维护系统的第一步。