先上代码:
User对象
public class UserDTO {
private int userId;
private String userName;
private int orgId;
private OrgDTO orgDTO;
}
Org对象
public Class OrgDTO {
private int orgId;
private String orgName;
}
工具类方法
public static <S, K, T> void oneToOne(List<S> sourceList, List<T> detailList, SafeFunction<S, K> sourceKey, SafeFunction<T, K> detailKey) {
Map<K, T> detailMap = detailList.stream().collect(Collectors.toMap(detailKey, Function.identity()));
for (S s : sourceList) {
K key = sourceKey.apply(s);
T detail = detailMap.get(key);
if (detail != null) {
// TODO How to call s.setDetail() ?
}
}
}
参数说明:
sourceList: 待填充数组
detailList: 填充物数组
sourceKey: sourceList与detailList的关联键
detailKey: detailList的关联键转换函数
好吧,以上参数说明比较难懂(我也不知道要怎么描述)……
举个场景例子:有一个UserDTO和OrgDTO,假设他们在数据表的关系是1对1,很多时候我们需要根据UserDTO里面的orgId查询对应的OrgDTO,然后根据orgId把OrgDTO填充进UserDTO里面。
传统的代码写法如下:
public void fillOrgDTO(List<UserDTO> userDTOs) {
Set<Integer> orgIds = userDTOs.stream().map(UserDTO::getOrgId).collect(Collectors.toSet());
List<OrgDTO> orgDTOs = orgDAO.findByIds(orgIds);
Map<Integer, OrgDTO> orgId2OrgDTOMap = orgDTOs.stream().collect(Collectors.toMap(OrgDTO::getOrgId, Function.identity()));
for (UserDTO userDTO : userDTOs) {
Integer orgId = userDTO.getOrgId();
OrgDTO orgDTO = orgId2OrgDTOMap.get(orgId);
if (orgDTO != null) {
userDTO.setOrgDTO(orgDTO);
}
}
}
我的想法是,有没有办法把以上这段代码抽象成一个通用的方法,这样就不用每次都写类似的代码。
然后就试着写出了oneToOne这个方法,不过去到TODO那里就不知道怎么写了。
理论上用反射可以做到(需要变更方法签名),但我不想用反射,因为不论从性能还是维护角度来看,反射都不是一个很好的选择。
之前也了解过Java8的Consumer和BiConsumer,但试了一下好像也没法实现我的需求,可能是我理解得不够。
所以,在此提出这个问题,看看大家有没有好的解决方案?
PS:方法签名可以变更,代码可任意修改,UserDTO、OrgDTO可以实现任意接口。
1 回答
![?](http://img1.sycdn.imooc.com/545865620001c45402760276-100-100.jpg)
慕容森
TA贡献1853条经验 获得超18个赞
首先建议尽量用JDK functional interfaces,如果可以。下面是代码:
public <S, T, K> void oneToOne(List<S> sourceList, List<T> detailList, Function<S, K> sourceKeyExtractor, Function<T, K> detailKeyExactor,
BiConsumer<S, T> action) {
// Make sure the keys in detail list are unique.
Map<K, T> detailMap = detailList.stream().collect(Collectors.toMap(detailKeyExactor, Function.identity()));
sourceList.stream().forEach(s -> action.accept(s, detailMap.getOrDefault(sourceKeyExtractor.apply(s), null)));
}
@Test
public void test_oneToOne() {
List<UserDTO> userList = null; // TODO
List<OrgDTO> orgList = null; // TODO
oneToOne(userList, orgList, s -> s.getOrgId(), t -> t.getOrgId(), (s, t) -> s.setOrgDTO(t));
}
其次,是一个设计的问题:因为 sourceKeyExtractor
, detailKeyExactor
离它操作的对象源比较远,可能会混淆或至少要记得一个对应关系,如果重构一下,把sourceKeyExtractor
移到前面一点,这样就一清二楚每个keyExtractor
操作的对象源。
public <S, T, K> void oneToOne(List<S> sourceList, Function<S, K> sourceKeyExtractor, List<T> detailList, Function<T, K> detailKeyExactor,
BiConsumer<S, T> action) {
// Make sure the keys in detail list are unique.
Map<K, T> detailMap = detailList.stream().collect(Collectors.toMap(detailKeyExactor, Function.identity()));
sourceList.stream().forEach(s -> action.accept(s, detailMap.getOrDefault(sourceKeyExtractor.apply(s), null)));
}
添加回答
举报
0/150
提交
取消