Skip to content

有关工程各个分层中方法参数定义的一些思考

一般 Java 后端开发中,习惯上会将工程分为 3 层,controller,service 和 dao。controller 负责接收解析校验请求和返回,service 处理业务逻辑,dao 执行数据库语句。

最近在重构一个工程,里面很多业务模块都是不同的人写的,每个人的代码风格和习惯都不同,看了各式各样的方法命名和参数定义,我也略有感触和思考。见过最狠的就是从 controller 层解析请求到 dao 层的数据库语句,其中涉及的方法全用 Map 作为参数一层一层向下传,真是让我大开眼界。

总体来说,定义方法参数有 2 种风格习惯:

  • 第一种是把所需要的变量作为一个个单独参数来传递,
  • 第二种则是将零散的变量组装成单个复合参数来传递,比如上面说的 Map,或者自定义的 DTO。

controller 层

先说说 controller 层,我建议用第一种方式,原因很简单,第一种方式能直观地看出接口需要的各个参数及类型,并直接在 controller 中对参数进行处理和校验,IDE 也会对未使用到的参数进行提醒。使用 DTO 则有可能会由于业务变更出现冗余字段,维护时容易忽视,久而久之 DTO 变臃肿,开发者也不能搞清楚接口到底需要参数。下面两种方式对比一下:

public Response addUser(@RequestParam("id") Integer id,
                        @RequestParam("age") Integer age,
                        @RequestParam("sex") Integer sex,
                        @RequestParam("name") String name) 
public Response addUser(RequestUserDTO requestUserDTO)

service 层

然后说说 service 层。
* 我认为在参数个数不是很多的情况下,建议用第一种方式,保持代码的简洁。
* 如果参数很多,或者业务变动频繁导致参数变化频繁的情况下,可以考虑使用第二种方式,第二种方式的优势就在于参数的变动不会影响到方法声明,我们只需要关心 DTO 中的变量,然后代码逻辑中处理这些变量。尤其在 service 层十分方便,service 一般都是一个接口对应一个实现类,因为不确定其他工程对原方法的依赖和调用,所以如果方法变更参数,接口和类中都必须保留原方法,增加新的方法来重载原方法,而用第二种方式传递参数,则可以避免这些修改。
* 在业务参数和逻辑参数混杂的情况下,可以使用两种方式结合,比如下面这样:

public PageInfo<User> userPageList(User user, Integer pageNum, Integer pageSize)
boolean updateUser(User user, String operator);

第一个方法使用了分页插件,所以分页参数并不会传递进 dao 层;第二个方法需要额外记录操作人

dao 层

最后看看 dao 层,我觉得 dao 层没什么多说的,两种方式都可以,看情况选择。

注意的地方

除了上面所说的工程中不同层级方法的参数定义方式,我还想说一些其他东西。
1. 不要用 Map。这真的真的很蠢,不能描述出所需变量的个数、名称和类型,如果存的变量类型不同还不能用泛型,只能取的时候强制转型。
2. 不同层不要用同一个 DTO。不同层都有自己的职责和意义,controller 层的 DTO 为了描述网络请求的参数,service 层的 DTO 为了描述业务相关的变量,dao 层的 DTO 为了描述数据库语句需要的参数。有的开发者为了方便,在开发一个功能时,定义一个字段很多的 DTO,从 controller 用到 dao,这也是很蠢的操作。不同层级的 DTO 放在各自的工程模块中,一方面可以解耦,另一方面可以让开发者加深工程化思想。

以上观点仅仅是我个人基于我当前的工作经验总结出来的,欢迎交流沟通。
我总结完才发现说的有点所谓的“理想化的最佳实践”了,工程中还是自由派比较多,大家写代码开心就好。

Published inThinking

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注