Skip to content

关于改进 IService 和 ServiceImpl 的建议 #5764

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
oracle-fusion-middleware-team opened this issue Nov 7, 2023 · 27 comments
Closed

关于改进 IService 和 ServiceImpl 的建议 #5764

oracle-fusion-middleware-team opened this issue Nov 7, 2023 · 27 comments

Comments

@oracle-fusion-middleware-team

当前使用版本(必填,否则不予处理)

3.5.4.1

该问题是如何引起的?(确定最新版也有问题再提!!!)

非问题。建议。

重现步骤(如果有就写完整)

N/A

报错信息

N/A

==========================

本来想建议直接去掉 IService 和 ServiceImpl,但考虑到有代码生成器和各种依赖,再加上国内做项目多数还是短平快,很多人不在乎领域设计,所以觉得还是做加法比较合适。

之所以有这个想法是基于如下两个观察:

  1. Mybatis-Plus 说到底还是Dao工具,而 IService 这个名字上溢了,不符合最佳实践(客观上鼓励了将 Dao 层当 Service 层)。它实际上的定位应该是 Repository。建议将 IService 改名为 IRepository,ServiceImpl 改名为 RepositoryImpl。
  2. 用户要想用这个接口时,需要先让自己的接口继承 IRepository,然后让实现类继承 RepositoryImpl 再实现用户接口。但随着面向领域设计概念的渐渐推开,许多用户不愿意让自己的接口依赖外部框架(即使中间加一层 BaseService)。根据DDD的概念,Repository接口是很重要的组件,它是划分领域模型与infra(细节)的界面:Service的实现属于领域模型,而Repository的实现属于infra(细节);Repository接口是二者共同依赖的抽象,是属于领域模型的;因此必然不想依赖外部框架。那么,用户Repository接口不继承IRepository,只让实现类继承 RepositoryImpl 可不可以呢?可以,只要自己定义个接口就可以(一般情况下,方法是 IRepository 的一个子集就够用了)。但此时实现类却无法直接利用很多方法,如getById。原因是getById是 IRepository 的一个默认方法。一个接口的默认方法不属于实现类,也就不能变成用户自定义接口的实现。用户得在实现类里重复实现一遍getById。因此建议将 IRepository 里的默认方法全部搬到 RepositoryImpl 里实现,IRepository变为老式纯接口。另外,RepositoryImpl 其实应该改叫 RepositorySupport,还原它实用工具的本质。

这样,我们获得了如下好处:

  1. 不会误导小朋友混淆Service层和Dao层,鼓励大家定义自己的业务接口。
  2. 完全不在乎的人可照旧用 IService 和 ServiceImpl。
  3. 想用DDD,但没有洁癖的同学可以改用 IRepository,并沿用已有的继承模式,即 MyRepository extends IRepository;MyRepositoryImpl extends RepositorySupport implements MyRepository。
  4. 有DDD洁癖的同学可定义自己的 Repository 接口,只利用 RepositorySupport 提供的实现。一些常用方法只要定义的和 IRepository 里的一样就能被 RepositorySupport 接住,最少化手写代码。

综上所述,建议:
1)新增 IRepository;与 IService 相同
2)新增 RepositorySupport;与 ServiceImpl 相同。
3)将原 IService 里的default方法搬到 RepositorySupport 里去实现;
4)为了向前兼容,IService、ServiceImpl 予以保留,加说明性文字。

附上参考实现(很简单)
extension(mybatisplus repository).zip

@startjava
Copy link

支持呦 这两个东东已经成为知乎或者脉脉上打击mp的主攻点了

@Jzow
Copy link

Jzow commented Nov 8, 2023

在DDD设计的时候,确实会有这个担忧,对于那些有洁癖的同学现阶段的mp设计的ISevice和ServiceImpl有一些歧义,正如你所提到的有些刚开始接触web开发的人员他们的关注点不是在框架本身

@totoro52
Copy link

totoro52 commented Nov 8, 2023

确实, IService 和 ServiceImpl把Dao和Serivce的关系模糊化了,我见过很多直接懒得继承方法而把业务逻辑直接写在了controller里,service久而久之就成为了名副其实的dao了

@Demonese
Copy link

Demonese commented Nov 9, 2023

Repository 从名称上来看确实比 Service 好很多,支持

@qmdx
Copy link
Member

qmdx commented Nov 10, 2023

感谢反馈当初设计上 IService 其实就是 IRepository 的等效功能,命名上可能是困惑,该问题后续会考虑您的建议调整

@oracle-fusion-middleware-team
Copy link
Author

赶紧行动吧!:D 这个change不复杂。好处是实实在在的,会有更多的人愿意采用mp,也免得别人拿这攻击mp。

@BubblingXuYijie
Copy link

还需要解决的这个问题,使用IService的批量方法,事务有问题
image

@cctyl
Copy link

cctyl commented Nov 14, 2023

可是,如果service 改为repository ,那mapper 属于哪一层呢? jpa中最后一层叫repository,上面是service, 而mybatis 最后一层是mapper,上一层是service,我感觉比较对应

@Demonese
Copy link

可是,如果service 改为repository ,那mapper 属于哪一层呢? jpa中最后一层叫repository,上面是service, 而mybatis 最后一层是mapper,上一层是service,我感觉比较对应

你这个思路就不对,有没有一种可能,mp的mapper其实也对应于jpa的repository,只不过mapper提供低级访问,repository提供高级访问,至于service应该是开发者自己实现的业务层,根本不应该出现在一个基础库里。

@totoro52
Copy link

可是,如果service 改为repository ,那mapper 属于哪一层呢? jpa中最后一层叫repository,上面是service, 而mybatis 最后一层是mapper,上一层是service,我感觉比较对应

这个跟框架没有关系,怎么叫都是对应那一层

@NiuXiangQian
Copy link

我们的DDD实现里目前是完全抛弃了IService的,确实不太适用,只用到了BaseMapper

@startjava
Copy link

我们的DDD实现里目前是完全抛弃了IService的,确实不太适用,只用到了BaseMapper

其实把IService中的方法合并到BaseMapper多好,还丰富了BaseMapper的功能,而且剔除了IService这个奇怪的东东。一举两得。

@shuangpai
Copy link

确实有问题,很多不懂的人拿起来都用,我接手的一个框架,有人这样用,搞的自定义缓存都不好加,对于高手可以区分开,对于不懂的人意识不到这样搞的坏处,删除这两个最好。

@Jzow
Copy link

Jzow commented Nov 27, 2023

IService本身应该起到工具的作用,如果按照DDD严格来区分,只需要在Mapper中继承BaseMapper就可以了,Service类自己实现业务代码不继承ServiceImpl和IService,自己的业务去调用Mapper的实现类方法就行。

但是这个还得看业务的体量,业务不是很复杂的情况下,可以梭哈写在一起,倒也无所谓,这更多的是一个设计模式和开发思想

@shuangpai
Copy link

IService本身应该起到工具的作用,如果按照DDD严格来区分,只需要在Mapper中继承BaseMapper就可以了,Service类自己实现业务代码不继承ServiceImpl和IService,自己的业务去调用Mapper的实现类方法就行。

但是这个还得看业务的体量,业务不是很复杂的情况下,可以梭哈写在一起,倒也无所谓,这更多的是一个设计模式和开发思想

嗯。正确的用法是只用BaseMapper的增改删三种类型方法,其他的走xml进行查询和权限过滤。

@fenston
Copy link

fenston commented Dec 22, 2023

确实,在DDD领域中IService显得不伦不类,初次学习,我就把他当Service来用了,但学过了DDD,发现确实有问题。
其实极端一点,直接改名,不考虑兼容性,强制纠正这一问题

@nieqiurong nieqiurong pinned this issue Apr 10, 2024
@nieqiurong
Copy link
Contributor

3.5.7 开始mapper合并service能力

@nieqiurong nieqiurong added this to the 3.5.7 milestone Apr 10, 2024
@nieqiurong
Copy link
Contributor

已发布3.5.7-SNAPSHOT
目前已有BaseMapper新增能力:
1.saveBatch 批量保存
2.updateBatchById 批量更新
3.saveOrUpdateBatch and saveOrUpdateBatch(自定义条件) 批量保存或更新
4.saveOrUpdate 保存或更新
5.deleteById,deleteBatchIds默认支持逻辑删除填充,增加重载方法参数是否需要填充处理.

@nieqiurong
Copy link
Contributor

后续规划,删除service层,只保留mapper,不再增加多层操作.

待定项:
1.批量操作是否需要控制批次大小

@rroads
Copy link

rroads commented Apr 10, 2024

已发布3.5.7-SNAPSHOT 目前已有BaseMapper新增能力: 1.saveBatch 批量保存 2.updateBatchById 批量更新 3.saveOrUpdateBatch and saveOrUpdateBatch(自定义条件) 批量保存或更新 4.saveOrUpdate 保存或更新 5.deleteById,deleteBatchIds默认支持逻辑删除填充,增加重载方法参数是否需要填充处理.

是不是可以把表关联查询的方法也加进来?我看原计划是4.0加的,结果4.0鸽了

@nieqiurong nieqiurong unpinned this issue Apr 14, 2024
@hitcp
Copy link

hitcp commented Apr 18, 2024

已发布3.5.7-SNAPSHOT 目前已有BaseMapper新增能力: 1.saveBatch 批量保存 2.updateBatchById 批量更新 3.saveOrUpdateBatch and saveOrUpdateBatch(自定义条件) 批量保存或更新 4.saveOrUpdate 保存或更新 5.deleteById,deleteBatchIds默认支持逻辑删除填充,增加重载方法参数是否需要填充处理.

是不是可以把表关联查询的方法也加进来?我看原计划是4.0加的,结果4.0鸽了

mybatis本来就支持的功能为什么还要去造轮子

@Demonese
Copy link

已发布3.5.7-SNAPSHOT 目前已有BaseMapper新增能力: 1.saveBatch 批量保存 2.updateBatchById 批量更新 3.saveOrUpdateBatch and saveOrUpdateBatch(自定义条件) 批量保存或更新 4.saveOrUpdate 保存或更新 5.deleteById,deleteBatchIds默认支持逻辑删除填充,增加重载方法参数是否需要填充处理.

是不是可以把表关联查询的方法也加进来?我看原计划是4.0加的,结果4.0鸽了

mybatis本来就支持的功能为什么还要去造轮子

建议看看 mybatis-plus-join,理论上有这个库后 mybatis-plus 不需要做联表功能了,能不用 mybatis 来写 sql 语句是最好的。

@hitcp
Copy link

hitcp commented Apr 18, 2024

已发布3.5.7-SNAPSHOT 目前已有BaseMapper新增能力: 1.saveBatch 批量保存 2.updateBatchById 批量更新 3.saveOrUpdateBatch and saveOrUpdateBatch(自定义条件) 批量保存或更新 4.saveOrUpdate 保存或更新 5.deleteById,deleteBatchIds默认支持逻辑删除填充,增加重载方法参数是否需要填充处理.

是不是可以把表关联查询的方法也加进来?我看原计划是4.0加的,结果4.0鸽了

mybatis本来就支持的功能为什么还要去造轮子

建议看看 mybatis-plus-join,理论上有这个库后 mybatis-plus 不需要做联表功能了,能不用 mybatis 来写 sql 语句是最好的。

建议优先看看官方的,https://github.com/mybatis/mybatis-dynamic-sql

@Demonese
Copy link

建议优先看看官方的,https://github.com/mybatis/mybatis-dynamic-sql

mybatis官方的体验欠佳。mybatis-plus-join只需要在mybatis-plus基础上把BaseMapper换成MPJBaseMapper就能支持联表,表达式写起来也很自然。

@hitcp
Copy link

hitcp commented Apr 19, 2024

建议优先看看官方的,https://github.com/mybatis/mybatis-dynamic-sql

mybatis官方的体验欠佳。mybatis-plus-join只需要在mybatis-plus基础上把BaseMapper换成MPJBaseMapper就能支持联表,表达式写起来也很自然。

个人觉得mp的主要任务是支持mybatis官方框架,拓展增强基础能力,而不是套壳一些其他的三方插件当自己功能

@Demonese
Copy link

Demonese commented Apr 19, 2024

而不是套壳一些其他的三方插件当自己功能

歪曲我的观点没意思,我说之前的是:

建议看看 mybatis-plus-join,理论上有这个库后 mybatis-plus 不需要做联表功能了


既然都用mybatis-plus了,那更应该利用好它繁荣的生态,通过拓展库来无缝集成新功能。特别是:项目已经大量使用mybatis-plus lambda查询的情况下。

这样mybatis-plus就不需要再去造联表查询轮子,保持精简,毕竟你也说了有dynamic sql,再不济还能直接写sql。

否则还不如把mybatis-plus从项目dependencies里删了,只用mybatis和官方配套的dynamic sql。


我还是想不通你为何会爆出这么神奇的言论,难道mybatis-plus开发团队,或者你干过这种事情?

@hitcp
Copy link

hitcp commented Apr 19, 2024

而不是套壳一些其他的三方插件当自己功能

歪曲我的观点没意思,我说之前的是:

建议看看 mybatis-plus-join,理论上有这个库后 mybatis-plus 不需要做联表功能了

既然都用mybatis-plus了,那更应该利用好它繁荣的生态,通过拓展库来无缝集成新功能。特别是:项目已经大量使用mybatis-plus lambda查询的情况下。

这样mybatis-plus就不需要再去造联表查询轮子,保持精简,毕竟你也说了有dynamic sql,再不济还能直接写sql。

否则还不如把mybatis-plus从项目dependencies里删了,只用mybatis和官方配套的dynamic sql。

我还是想不通你为何会爆出这么神奇的言论,难道mybatis-plus开发团队,或者你干过这种事情?

1.理论上有这个库指的不是mp理论上有这个库?那不就是套壳?

2.我看到mp现有功能都是基于基础框架自己做实现的,根本不会去集成一些不知名小众且可能随时停更断维护的类库。

3.而且我觉得你应该就是论事!什么叫做神奇的言论?多神奇啊?还我或官方干过这事,我还觉得你干过呢

@baomidou baomidou locked and limited conversation to collaborators Apr 19, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests