如何编写支持多参数函数的泛型toSlice流转换方法?
问题
我现有一个用于将Page对象转换为Slice的泛型方法:
public static <T,R> Slice<R> toSlice(final Page<T> source, Function<T,R> transform) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(transform) .collect(Collectors.toList())) .build(); }
平时我是这样使用该方法的:
return SliceFactory.toSlice( someDao.findAll( predicate, PageRequest.of(page, PAGE_SIZE, Sort.by(Sort.Direction.DESC, DEFAULT_SORTING_PROPERTY))), dtoFactory::toSomeDto);
现在需要给dtoFactory.toSomeDto()传入额外参数,请问如何改造现有toSlice方法为支持该需求的泛型方法?
解决方案
1. 支持单个额外参数的改造
如果仅需传入一个额外参数,可以将原方法的Function<T,R>替换为BiFunction<T, U, R>,新增泛型参数U来定义额外参数的类型:
public static <T, U, R> Slice<R> toSlice(final Page<T> source, final U extraParam, final BiFunction<T, U, R> transform) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(item -> transform.apply(item, extraParam)) .collect(Collectors.toList())) .build(); }
使用示例:
假设toSomeDto需要接收一个UserContext类型的额外参数,调用方式如下:
UserContext userContext = new UserContext(); return SliceFactory.toSlice( someDao.findAll( predicate, PageRequest.of(page, PAGE_SIZE, Sort.by(Sort.Direction.DESC, DEFAULT_SORTING_PROPERTY))), userContext, dtoFactory::toSomeDto);
2. 支持多个额外参数的改造
若需传入多个参数,推荐采用参数封装的方式,也可使用可变参数(不推荐):
方式一:自定义参数类封装
将所有额外参数封装到一个专用类中,比如ConvertParams,再通过BiFunction传递:
// 自定义参数封装类 public class ConvertParams { private UserContext userContext; private Locale locale; // 构造器、Getter、Setter } // 改造后的toSlice方法 public static <T, P, R> Slice<R> toSlice(final Page<T> source, final P params, final BiFunction<T, P, R> transform) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(item -> transform.apply(item, params)) .collect(Collectors.toList())) .build(); }
使用示例:
ConvertParams params = new ConvertParams(userContext, Locale.CHINA); return SliceFactory.toSlice( someDao.findAll(predicate, PageRequest.of(page, PAGE_SIZE, Sort.by(Sort.Direction.DESC, DEFAULT_SORTING_PROPERTY))), params, dtoFactory::toSomeDto);
方式二:可变参数结合Function(不推荐)
这种方式无需封装类,但需要手动强转参数,可读性与安全性较差:
@SuppressWarnings("unchecked") public static <T, R> Slice<R> toSlice(final Page<T> source, final Function<T, Object[], R> transform, final Object... extraParams) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(item -> transform.apply(item, extraParams)) .collect(Collectors.toList())) .build(); }
使用示例:
return SliceFactory.toSlice( someDao.findAll(predicate, PageRequest.of(page, PAGE_SIZE, Sort.by(Sort.Direction.DESC, DEFAULT_SORTING_PROPERTY))), (item, params) -> dtoFactory.toSomeDto(item, (UserContext) params[0], (Locale) params[1]), userContext, Locale.CHINA);
3. 保留原有方法兼容性
如果不想破坏现有代码的调用逻辑,可以通过方法重载同时保留原有的无额外参数版本:
// 原有方法保持不变 public static <T,R> Slice<R> toSlice(final Page<T> source, Function<T,R> transform) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(transform) .collect(Collectors.toList())) .build(); } // 新增支持单个额外参数的重载方法 public static <T, U, R> Slice<R> toSlice(final Page<T> source, final U extraParam, final BiFunction<T, U, R> transform) { return Slice.<R>builder() .totalPages(BigInteger.valueOf(source.getTotalPages())) .pageData(source.stream() .map(item -> transform.apply(item, extraParam)) .collect(Collectors.toList())) .build(); }
这样原有代码无需修改,新需求场景直接使用重载后的方法即可。
内容的提问来源于stack exchange,提问作者benjaminv2
相关产品推荐
相关产品推荐

