前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >简化补充关联对象的业务代码

简化补充关联对象的业务代码

作者头像
十毛
发布2019-11-26 13:49:27
4490
发布2019-11-26 13:49:27
举报

业务项目中经常有跨表对象或者跨服务的对象,对象之间使用Id关联,但是返回到调用方时,又需要根据id补充完整的关联对象。这种模式非常常用,所以写了一个工具类,简化了这个步骤

场景描述

问题中有分类信息,但是默认保存在库表中的只有分类Id(categoryId),但是接口返回给调用方的时候,需要补充完整的Category信息

  • Question.java
代码语言:javascript
复制
@Data
public class Question {
    private Integer id;
    /**
     * 分类ID.
     */
    private Integer categoryId;

    private Category category;

    /**
     * 问题.
     */
    private String question;
}
  • Category.java
代码语言:javascript
复制
@Data
public class Category {
    private Integer id;
    private String name;
}

默认情况下,从数据库中查询问题列表时,只有categoryId,没有CategoryCategory需要根据id再进行远程调用获取(有的是可以通过联表查询)

  • 使用方式
代码语言:javascript
复制
SupplementUtil<Question, Integer, Category> supplement = SupplementUtil.<Question, Integer, Category>builder()
        .idProviderForTarget(Question::getCategoryId)
        .idProviderForObj(Category::getId)
        .objSetter(Question::setCategory)
        .build();
supplement.supplementWithConverter(questions, categoryManager::getByList);

使用这种方式可以减少很多胶水代码

SupplementUtil定义

  • SupplementUtil.java
代码语言:javascript
复制
/**
 * 对象补充器.
 * 通过Target中的ID,填充ID对应的对象Obj到Target
 *
 * @param <Target> 被补充的目标对象
 * @param <Id>     补充对象的ID
 * @param <Obj>    补充的对象
 * @author tenmao
 * @since 2019/11/13
 */
@Builder
public class SupplementUtil<Target, Id, Obj> {
    /**
     * Target中获取Obj的Id的方法.
     */
    @NonNull
    private Function<Target, Id> idProviderForTarget;

    /**
     * Obj中获取Id的方法.
     */
    @NonNull
    private Function<Obj, Id> idProviderForObj;

    /**
     * Target中设置Obj的方法.
     */
    @NonNull
    private BiConsumer<Target, Obj> objSetter;

    /**
     * 是否要求ID对应的Obj一定存在.
     */
    private boolean requireExists = true;

    /**
     * 如果ID赌赢的Obj不存在,则使用该默认值.
     */
    private Function<Id, Obj> defaultObj = null;

    /**
     * 使用ID到Obj的转换器来补充目标对象Targets
     *
     * @param targets   目标对象
     * @param converter ID到Obj的转换器
     */
    public void supplementWithConverter(List<Target> targets, Function<List<Id>, List<Obj>> converter) {
        //获取所有Id
        List<Id> ids = targets.stream().map(idProviderForTarget).filter(Objects::nonNull).collect(Collectors.toList());
        if (ids.isEmpty()) {
            return;
        }

        //获取Id列表对应的Obj列表,并转换为Map
        Map<Id, Obj> objMap = converter.apply(ids).stream().collect(Collectors.toMap(idProviderForObj, Function.identity()));

        supplementWithMap(targets, objMap);
    }

    /**
     * 使用ID到Obj的Map来补充目标对象Targets
     *
     * @param targets 目标对象
     * @param objMap  ID到Obj的Map
     */
    public void supplementWithMap(List<Target> targets, Map<Id, Obj> objMap) {
        batchSupplement(targets, idProviderForTarget, objSetter, objMap, requireExists, defaultObj);
    }

    /**
     * 批量根据ID扩充对象信息.
     *
     * @param targets       扩充对象的目标对象
     * @param idProvider    ID提供方法
     * @param objSetter     对象设置器
     * @param objMap        ID到对象的Map
     * @param requireExists 是否要求必须(如果是,但是没有存在,则会抛出异常{@link IllegalArgumentException})
     * @param defaultObj    如果没有匹配到则使用默认值
     * @param <Target>      扩充对象的目标对象
     * @param <Id>          ID
     * @param <Obj>         ID对应的对象
     */
    public static <Target, Id, Obj> void batchSupplement(List<Target> targets,
                                                         Function<Target, Id> idProvider,
                                                         BiConsumer<Target, Obj> objSetter,
                                                         Map<Id, Obj> objMap,
                                                         boolean requireExists,
                                                         Function<Id, Obj> defaultObj) {
        if (targets == null || idProvider == null || objSetter == null || objMap == null) {
            throw new IllegalArgumentException("parameter for supplement should not be empty");
        }
        for (Target target : targets) {
            Id id = idProvider.apply(target);
            if (id != null) {
                Obj o = objMap.get(id);
                if (o == null && requireExists) {
                    throw new IllegalArgumentException(String.format("id:%s cannot convert to object", id));
                }
                objSetter.accept(target, o != null ? o : defaultObj.apply(id));
            }
        }
    }
}
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 场景描述
  • SupplementUtil定义
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档