- VO 实现 XXXFetcher 接口,实现对应方法,提供关联数据并完成数据绑定
- 使用 XXXFetcherExecutor 完成数据绑定
4.2. 重构绑定逻辑接下来让我们一起聚焦于绑定逻辑,先对比下上述的UserVOFetcherExecutor 与下面的 AddressVOFetcherExecutor,找到里面的变化与不变:
@Componentpublic class AddressVOFetcherExecutorV1 {@Autowiredprivate AddressRepository addressRepository;public void fetch(List<? extends AddressVOFetcherV1> fetchers){// 获取关联信息List<Long> ids = fetchers.stream().map(AddressVOFetcherV1::getAddressId).distinct().collect(Collectors.toList());// 查询关联数据List<Address> addresses = addressRepository.getByIds(ids);// 转为为 MapMap<Long, Address> addressMap = addresses.stream().collect(toMap(address -> address.getId(), Function.identity()));// 依次进行数据绑定fetchers.forEach(fetcher -> {Long addressId = fetcher.getAddressId();Address address = addressMap.get(addressId);if (address != null){// 转换为 VOAddressVO addressVO = AddressVO.apply(address);// 将数据写回到结果fetcher.setAddress(addressVO);}});}}仔细观察,会发现:【不变】逻辑骨架基本一致,基本是由:
- 获取关联信息
- 查询关联数据
- 将其转换为 Map
- 讲数据转化为 VO
- 将 VO 绑定到结果对象
- 从什么接口中获取关联信息
- 如何查询关联数据
- 转换为 Map 的键是什么
- 如何将数据转换为 VO
- 如何完成数据的绑定
答案便是:模板方法模式
整体思想为:
- 将不变的逻辑骨架封装在父类方法
- 将变化的实现细节放在子类中进行扩展

文章插图
抽取公共父类如下:
abstract class BaseItemFetcherExecutor<FETCHER extends ItemFetcher, DATA, RESULT>implements ItemFetcherExecutor<FETCHER>{@Overridepublic void fetch(List<FETCHER> fetchers) {// 获取关联信息List<Long> ids = fetchers.stream().map(this::getFetchId).distinct().collect(Collectors.toList());// 查询关联数据List<DATA> datas = loadData(ids);// 转为为 MapMap<Long, List<DATA>> dataMap = datas.stream().collect(groupingBy(this::getDataId));// 依次进行数据绑定fetchers.forEach(fetcher -> {Long id = getFetchId(fetcher);List<DATA> ds = dataMap.get(id);if (ds != null){// 转换为 VOList<RESULT> result = ds.stream().map( data -> convertToVo(data)).collect(Collectors.toList());// 将数据写回到结果setResult(fetcher, result);}});}protected abstract Long getFetchId(FETCHER fetcher);protected abstract List<DATA> loadData(List<Long> ids);protected abstract Long getDataId(DATA data);protected abstract RESULT convertToVo(DATA data);protected abstract void setResult(FETCHER fetcher, List<RESULT> result);}基于 BaseItemFetcherExecutor 的 UserFetcherExecutor 如下:@Componentpublic class UserVOFetcherExecutorV2extends BaseItemFetcherExecutor<UserVOFetcherV2, User, UserVO>{@Autowiredprivate UserRepository userRepository;@Overrideprotected Long getFetchId(UserVOFetcherV2 fetcher) {return fetcher.getUserId();}@Overrideprotected List<User> loadData(List<Long> ids) {return this.userRepository.getByIds(ids);}@Overrideprotected Long getDataId(User user) {return user.getId();}@Overrideprotected UserVO convertToVo(User user) {return UserVO.apply(user);}@Overrideprotected void setResult(UserVOFetcherV2 fetcher, List<UserVO> userVO) {if (CollectionUtils.isNotEmpty(userVO)) {fetcher.setUser(userVO.get(0));}}@Overridepublic boolean support(Class<UserVOFetcherV2> cls) {// 暂时忽略,稍后会细讲return UserVOFetcherV2.class.isAssignableFrom(cls);}}UserVOFetcherExecutor究竟发生什么变化呢?好像变得更复杂了: