关于web后端分层的疑问
简单来说 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.
2. 在 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 类似功能的?
3. 什么是数据实体? 是否 controller service dao 是一一对应的,如果不是, 能否举几个例子。 主要是 DAO 和 service.
三层架构和 DDD 的优缺点建议不再本贴讨论。担心歪楼。 谢谢大家啦! 建立楼主学习一下领域驱动设计, 就知道啥是业务逻辑层, 啥是应用程序层,
我之前也简单翻译了一篇相关的文章
实现领域驱动设计 - 使用ABP框架 - 领域逻辑 & 应用逻辑
https://www.cnblogs.com/broadm/p/16408812.html 简单举个例子:
比如你的系统有用户注册功能, 通过账号密码注册, 注册完成后要给用户发个邮件
你的应用程序就需要提供一个注册服务, 这个服务就干2件事情, 注册+发邮件, 这里注册就是核心业务逻辑(领域逻辑), 发邮件就是通用业务(非领域逻辑,又叫应用程序逻辑)
为啥这么说,比如,你现在又要开发一个通过手机号注册的功能,现在就不需要发邮件了, 你就发现, 哦, 原来注册才是必须得, 发邮件是根据用例不同,不一定需要的, 就可以区分了, 发邮件不是核心业务逻辑, 它是随用例变化而变化的, 这就是应用逻辑 所以根据这个用例, 就可以指导你设计接口了, 你就可以很明显的分为2个部分,注册+发邮件
//根据账号密码注册
voidRegisterByAccount(string account, string password)
{
var user = UserDomainService.CreateUserByAccount(account, password);//这里面就可以涉及更详细的业务逻辑了, 比如验证用户名唯一,合法性等等
EmailAppService.Send(....);//发邮件
}
//根据手机号注册
voidRegisterByMobile(string mobile, string code)
{
var user = UserDomainService.CreateUserByMobile(mobile, code);//通过手机号和短信验证码, 校验数据合法性等
}
至于三层架构的里面的Controller可以简单理解为 应用程序层, 就是编排用例的执行顺序 (比如,依次调用用户服务提供的注册功能 + 邮件服务提供的发邮件功能)
Service层可以简单理解为业务逻辑层, 处理核心业务的地方, 比如:用户注册的具体实现
Dao就是 数据访问层,就是和数据库打交道的, 比如, 用户注册里面就可以用到dao, 用户注册要保证用户名唯一, 里面就可以使用 dao访问数据库, 查看这个用户名是否被占用了,
Dao就是 把数据访问和数据库解耦用的,, 比如你要 从sqlserver 数据库切换到 mysql数据库,很多sql都要修改的,你直接再实现一个 dao就行,只要在使用的地方一来抽象的接口就行, 不用关心底层是什么数据库, 所以dao就是一个抽象层, 你要是吧查询语句直接写在 Service里面,要是业务有变动, 你就得修改所有使用的地方了, 累死你{:1_918:} Broadm 发表于 2024-5-7 14:31
所以根据这个用例, 就可以指导你设计接口了, 你就可以很明显的分为2个部分,注册+发邮件
//根据账号密 ...
谢谢大佬,打了这么多字. 等我下班仔细拜读.
接下来几天我的免费评分全是大佬的{:301_993:}
Broadm 发表于 2024-5-7 14:31
所以根据这个用例, 就可以指导你设计接口了, 你就可以很明显的分为2个部分,注册+发邮件
//根据账号密 ...
大佬你好啊,
仔细拜读了你写回复.
让我对DDD又有了新的认识,
但是大佬能不能再给讲讲你说的DAO的方法名字是如何定义的.
譬如你说的, 查询用户名是否被占用.
UserDao.Exist(userId)
还是
user = UserDao.getUserById(userId)
if user is not null:
xxx
还是说无所谓? chaleaoch 发表于 2024-5-8 00:05
大佬你好啊,
仔细拜读了你写回复.
让我对DDD又有了新的认识,
正常来说, 提供一个根据用户名查询的方法就行了,但是如果这个查询是否被占用的使用的地方很多就可考虑单独封装一下, 写代码嘛,只要还是要考虑复用, 没有统一的答案,看使用场景等等综合考虑 Broadm 发表于 2024-5-9 08:59
正常来说, 提供一个根据用户名查询的方法就行了,但是如果这个查询是否被占用的使用的地方很多就可考虑 ...
明白, 归根到底, 实际的项目和网上的文章, 一个是理论一个是实践.,
还是有一点点区别的哈.
是这样吧. chaleaoch 发表于 2024-5-9 09:43
明白, 归根到底, 实际的项目和网上的文章, 一个是理论一个是实践.,
还是有一点点区别的哈.
是的,看实际需要, 也不要过度设计{:1_921:}
页:
[1]