如何实现通用的对象填充方法

发布于 2022-09-05 09:09:16 字数 2445 浏览 20 评论 0

先上代码:

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的关联键转换函数

好吧,以上参数说明比较难懂(我也不知道要怎么描述)……

举个场景例子:
有一个UserDTOOrgDTO,假设他们在数据表的关系是1对1,很多时候我们需要根据UserDTO里面的orgId查询对应的OrgDTO,然后根据orgIdOrgDTO填充进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的ConsumerBiConsumer,但试了一下好像也没法实现我的需求,可能是我理解得不够。

所以,在此提出这个问题,看看大家有没有好的解决方案?

PS:方法签名可以变更,代码可任意修改,UserDTO、OrgDTO可以实现任意接口。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

把梦留给海 2022-09-12 09:09:16

首先建议尽量用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)));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文