用Map的方式消除if-else的进阶方案
用Map的方式消除if-else的进阶方案
场景
在SpringBoot项目中,有一个表,内部有n种数据类型,每种数据的生成逻辑有区别,若是用if-else或者switch-case的方式,判断链回显得比较冗余
实现
借助函数式接口,我们可以将方法存入到Map中,在调用时,只需要根据类型获取对应的方法,并且执行该方法即可获取到需要生成的数据
在函数式接口的基础上,引入泛型,做一个通用类,通用类中封装了Map的put、get方法,我们可以很方便的调用,即可完成逻辑的统一
函数式接口采用
java.util.function.Function,通用类的泛型会传递到函数式接口中,指定了
-
通用类
/** * @author iAuzre 2024/8/15 11:09 */ public class InitBaseData<T, R> { private static final Logger log = LoggerFactory.getLogger(InitBaseData.class); private final Map<String, Function<T, List<R>>> map = new ConcurrentHashMap<>(); protected void register(String key, Function<T, List<R>> function) { if (Objects.isNull(function)) { log.warn("function is null! key:{}", key); return; } map.put(key, function); } protected Function<T, List<R>> getFunction(String type) { return map.get(type); } } -
子类实现
/** * 管会分析-人工成本及手续费用表(MaLaborHandlingFee)应用服务 * * @author iAuzre 2024-08-15 15:51:53 */ @Service public class MaLaborHandlingFeeServiceImpl extends InitBaseData<String, MaLaborHandlingFee> implements MaLaborHandlingFeeService { private static final Logger log = LoggerFactory.getLogger(MaLaborHandlingFeeServiceImpl.class); private final MaLaborHandlingFeeRepository maLaborHandlingFeeRepository; @Autowired public MaLaborHandlingFeeServiceImpl(MaLaborHandlingFeeRepository maLaborHandlingFeeRepository) { this.maLaborHandlingFeeRepository = maLaborHandlingFeeRepository; } /** * 将各种类型基础数据生成逻辑注册到函数式接口 Map 中 * <p> * 注册、获取方法来自于父类 {@link InitBaseData} * <p> * 其中,父类封装了注册、获取方法提供使用 */ @PostConstruct public void registerBaseDataFunction() { register(MaLaborHandlingFee.TableType.TABLE1.getName(), maLaborHandlingFeeRepository::initDataTable1); register(MaLaborHandlingFee.TableType.TABLE2.getName(), maLaborHandlingFeeRepository::initDataTable2); register(MaLaborHandlingFee.TableType.TABLE3.getName(), maLaborHandlingFeeRepository::initDataTable3); register(MaLaborHandlingFee.TableType.TABLE4.getName(), maLaborHandlingFeeRepository::initDataTable4); register(MaLaborHandlingFee.TableType.TABLE5.getName(), maLaborHandlingFeeRepository::initDataTable5); } @Override public Page<MaLaborHandlingFee> selectList(PageRequest pageRequest, MaLaborHandlingFee maLaborHandlingFee) { Page<MaLaborHandlingFee> page = PageHelper.doPageAndSort(pageRequest, () -> maLaborHandlingFeeRepository.selectList(maLaborHandlingFee)); if (CollectionUtils.isNotEmpty(page)) { return page; } // 查询数据为空,根据表类型、期间生成基础数据 initBaseData(maLaborHandlingFee.getTableType(), maLaborHandlingFee.getGlPeriod()); // 重查返回数据 return PageHelper.doPageAndSort(pageRequest, () -> maLaborHandlingFeeRepository.selectList(maLaborHandlingFee)); } /** * 根据数据类型、期间生成基础数据 * <p> * 需注意:为防止重复生成数据,只能生成一次,方法加了操作锁,同时内部会校验对应数据是否已经生成 * <p> * 通过 insert 数据之前校验数据数量来乐观的保证微服务架构下锁成功 * * @param tableType 数据类型{@link MaLaborHandlingFee.TableType} * @param glPeriod 期间 */ private synchronized void initBaseData(String tableType, String glPeriod) { Function<String, List<MaLaborHandlingFee>> function = getFunction(tableType); Objects.requireNonNull(function, "表类型异常或对应方法未注册成功!表类型:" + tableType); List<MaLaborHandlingFee> baseList = function.apply(glPeriod); // 获取数据数量,若不为0,则跳过insert int dataCount = maLaborHandlingFeeRepository.selectCountByCondition( Condition.builder(MaLaborHandlingFee.class) .where(Sqls.custom() .andEqualTo(MaLaborHandlingFee.FIELD_TABLE_TYPE, tableType) .andEqualTo(MaLaborHandlingFee.FIELD_GL_PERIOD, glPeriod)) .build()); if (dataCount != 0) { log.warn("存在重复生成数据情况,跳过insert, tableType:{}, glPeriod:{}", tableType, glPeriod); return; } maLaborHandlingFeeRepository.batchInsertSelective(baseList); } }我们在使用的时候继承该通用父类,并指定函数式接口的入参、返回值的泛型对应值,即可完成父类内的初始化
上述代码中:
initBaseData方法使用了synchronized主要是为了防止高并发场景下重复生成数据的问题,但单用synchronized来做锁并不能限制住微服务场景,为了解决这一问题,在我们准备insert之前,还查询了一次表中该类型数据的数量以防止重复实现,算是分布式场景下的一种乐观锁实现方式。
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 iAuzre
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果
音乐天地