使用 Java 8 函数式编程减少重复代码:Function 应用 |
您所在的位置:网站首页 › java函数代码 › 使用 Java 8 函数式编程减少重复代码:Function 应用 |
问题背景
我们的项目中常常会对数据做一些校验,例如添加一个用户,我们需要校验这些内容: 用户名称是否已被使用 邮箱是否已被使用 工号是否已被使用 手机号是否已被使用等等这些校验 添加用户方法 @Override @Transactional(rollbackFor = Exception.class) public void add(UserAddDTO dto) { // 校验名称是否重复 throwExceptionWhenNameExists(dto); // 校验邮箱是否重复 throwExceptionWhenEmailExists(dto); // 校验手机号是否重复 throwExceptionWhenPhoneExists(dto); // 校验工号是否重复 throwExceptionWhenWorkNoExists(dto); SysUser user = init(dto); // 保存用户 save(user); // 保存用户角色 saveRoles(dto, user); // 保存用部门 saveDept(dto, user); } 校验名称是否重复 private void throwExceptionWhenNameExists(UserAddDTO dto) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper(); wrapper.eq(SysUser::getUsername, dto.getUsername()); long count = count(wrapper); if(count > 0) throw new RuntimeException("用户名称已被使用"); } 校验邮箱是否重复 private void throwExceptionWhenEmailExists(UserAddDTO dto) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper(); wrapper.eq(SysUser::getEmail, dto.getEmail()); long count = count(wrapper); if(count > 0) throw new RuntimeException("邮箱已被使用"); } 问题分析上面的这种做法,对于每个字段,我们都要写一个方法。感觉非常的麻烦,而且一个项目有很多这样的地方。 如果每个地方都是这种写法,就会浪费比较多的时间。 我们可以发现,像是这种校验都有一个共同的特征,就是通过某个字段统计在表中的数量,我们是不是可以像 MyBatis-Plus 一样,将获取该字段的方法传递过去就行了? 对于要验证的字段,我们可以通过 SysUser::getUserName、SysUser::getPhone 这种方式传递过去,然后再将对应的值传过去。最终期望的结果是这样的: // 校验名称是否重复 assertFieldNoRepeat(dto.getUserName(), SysUser::getUserName, "用户名称已被使用"); // 校验邮箱是否重复 assertFieldNoRepeat(dto.getUserName(), SysUser::getUserName, "邮箱已被使用"); //......以终为始,以结果为导向反过来推导: 首先,我们将需要校验的值传进去 其次,再将这个值对应的字段传进去 然后,将异常消息给传进去 这样子,同一个类,无论那个字段,都可以用这种方式校验是否重复了 最终得出的方法是这样的 优化后的方法 /** * 重复字段校验 * @param getColumn 被验证的字段 * @param val 被校验的值 * @param msg 异常消息 */ private void assertFieldNoRepeat(SFunction getColumn, Object val, String msg) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper(); wrapper.eq(getColumn, val); long count = count(wrapper); if(count > 0) throw new RuntimeException(msg); }这样子,我们就不用为每一个字段都编写一个校验方法了。 再优化一下除了 SysUser 之外,是不是其他的表也存在很多这样的场景。 我们是不是可以将这个方法再提取一下,变成一个工具类。 对于不同的类,我们可以通过泛型的方式传进来,对于 count 方法,我们是不是可以同样使用 Function 的方式传进来。我们最终期望的效果是这样的: // SysUser 校验名称是否重复 FieldValidUtil.assertFieldNoRepeat(dto.getUsername(), SysUser::getUsername, this::count, "用户名称已被使用"); // SysUser 校验邮箱是否重复 FieldValidUtil.assertFieldNoRepeat(dto.getEmail(), SysUser::getEmail, this::count, "邮箱已被使用"); // 或者别的类 // Material 物料校验编码是否重复 FieldValidUtil.assertFieldNoRepeat(materialDto.getCode(), Material::getCode, materialService::count, "物料编码已被使用");以终为始,通过反方向推导: 首先,我们需要将被校验的值传入, 其次,再将这个值对应的类、字段传进去, 然后,再通过这个类的 Service 的 count 方法统计数量 最终推导出的工具类的实现是这样子的: import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.support.SFunction; /** * 字段校验工具 */ public class FieldValidUtil { /** * 重复字段校验 * @param val 被校验的值 * @param getColumn 被校验的列 * @param method 指定的方法 * @param msg 异常消息 */ public static void assertFieldNoRepeat(Object val, SFunction getColumn, SFunction method, String msg) { LambdaQueryWrapper wrapper = new LambdaQueryWrapper(); wrapper.eq(getColumn, val); Long count = method.apply(wrapper); if(count > 0) throw new RuntimeException(msg); } } 总结我们要善于发现工作中的这些痛点,然后分析这些问题的共同点,进行抽象归纳,找到共性,然后想办法将这些同类型的问题用同一种方式解决,避免将时间浪费在重复的事情上。 |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |