关于后端开发分层的疑问?

简单来说 controller service dao 三层。

controller 和 service 之间的分层相对比较清晰, 业务逻辑和显示逻辑的拆分, 譬如 MQ/http/RPC 和业务分离。

service 和 dao 的区分我有点搞不懂。主要是因为分不清什么是存储逻辑(非业务逻辑)什么是业务逻辑。 尤其是加入了 manager 层之后。

因为是 python 后端, 所以很自然的将业务逻辑加到 Model 上。 (我理解这里的 Model 是指业务 Model ) UserModel.is_super() 带业务的查询。
或者
UserModel.objects.all() 原生将 permissons,groups ,Commany,等等一起都带过来了。
或者
UserModel.* 做一些跨表的操作。

我的问题:

什么是业务逻辑, 什么是非业务逻辑。
我的理解是,客户看不到的逻辑都算非业务逻辑, 譬如
1.1 表结构,表关联关系等。
UserManager.delete()和DepartmentManager.delete() 这俩可以同时包含删除关联关系表( UserDeptModel )的能力。不是二取一。 同理 save 也是。 如果没有 manager 层, 那么我的理解 Dao 是可以做连/跨表操作的,只要这个跨表操作和业务无关,没必要在 service 调用两次 dao 。

class UserManager:
    def delete():
        UserDao.delete()
        UserDeptDao.delete()
class DepartmentManager:
    def delete():
        DepartmentDao.delete()
        UserDeptDao.delete()

1.2 密码加盐。
用户最多只需要知道你的密码是不明文保存就可以了。 加盐动作可以放在 DAO/Manager 层处理。

class UserDao:
    def make_password(passwd):
        return salt(passwd)
    def save():
        passwd = self.make_password(passwd)
        self.passwd = passwd
        super.save()

1.3 DAO 层的方法命名和设定
是否可以类似get_super_user 这种带有非业务逻辑(假设这个 super 与业务逻辑无关),但是具有明显语义的方法名?还是只能get_user_by_type("super")
1.4 http 请求也可以封装层 dao. 譬如后端有一些依赖(另一个 team 提供支持), 我可以将这些依赖封装成 dao, 而不是 service.

  1. 在 django/flask 中, 很容易实现 django filter 的功能。 https://www.django-rest-framework.org/api-guide/filtering/
    https://django-filter.readthedocs.io/en/stable/
    甚至于在 ModelViewSet 中直接集成了 filter, https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py#L33 如果用 python 做三层架构且想实现类似 django filter 功能的话, 那么 DAO 中一定需要传入 request 参数。且层层穿透。在没有 spring 这种自动注入框架的帮助下,如何处理类似的问题? java 中是如何实现类似 django filter 类似功能的?
  2. 什么是数据实体? 是否 controller service dao 是一一对应的,如果不是, 能否举几个例子。 主要是 DAO 和 service.

三层架构和 DDD 的优缺点建议不再本贴讨论。担心歪楼。 谢谢大家啦!

阅读 1.5k
3 个回答

问题太大了,只能从java的说一些比较宏观抽象的

分层的目的本身是为了按照职责对系统进行拆分,由外而内:

  1. 暴露对外的一层,XXController,很薄,仅作为入口
  2. 执行业务的一层,XXService,最厚最核心
  3. 执行对‘内’的一层,通常是访问数据库,但是也可能是访问三方接口,本地文件等等

所以service和dao的区别就很明确:dao只做对接,不承接业务
比如说有一个‘创建用户‘的逻辑,service里会’查询用户名是否重复‘然后’创建用户‘,对应的dao里就会有’根据用户名查询用户‘和’保存用户‘的方法

至于持久如何实现,是active record模式还是dao模式,其实大差不差
DDD和贫血模型其实也并不完全冲突,实际工程体验下来,贫血模型还是更容易理解一点

我理解分层的思想是 Controller 层可以重复调用 Service 层的方法,且 Service 层的方法可以嵌套调用 Service 层的方法,在设计 Service 层的方法时需要有一定经验。

若你对如何分层有疑问,我可以提供一点点思路。

若你要问为什么要分层?我的回答是分就对了。

若你要分怎么分层?我的回答是
在 Controller 层若遇到需要写两行及两行以上代码的,就要抽象到 Service 层。(抽象成为一个方法名容易理解,且预防以后重复调用,其次是尽可能将 Controller 层仅做错误处理)
在 Service 层若遇到需要写 SQL 语句的,每一个 SQL 语句都要抽象到 DAO 层。

这东西不是那么死板的规定,也不是有唯一正确答案的问题,你自己梳理一个合理的理解即可。目前我是controller只负责定义接口,调用service,并且封装为通用应答,service实现全部代码逻辑,dao是两个作用,因为使用mp,所以一个作用是mp生成的默认方法,另一个是定义sql接口,不会包含代码逻辑

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题