重点在 SearchParam 参数的设计。 先思考下SearchParam 可能有哪些类型的条件? 相等性比较(eq, neq), 不等性比较 (lt, gt, lte, gte),集合包含 (in) , 范围判断 ( range) , 模糊匹配(match) , 否定判断 (not)。绝大多数搜索基本落在这个范围内。
我能想到的,有三种方案:
将 SearchParam 设计成一个 Map[String, T or Object] ,value 是泛型或 Object 类型。 可以在 Map 里的 value 中塞入各种具体条件类型。这样需要从 value 中解析出各种条件类型,很容易出错,且不直观。
将 SearchParam 设计成一个 Object ,使用业务方定义的业务pojo进行赋值; 在实现内部,采用反射的方式来解析这个 Object ,得到搜索条件。通常,容易出错,且不直观。
将 SearchParam 设计成一个复合条件 Condition ,详见 “设计模式之组合模式:实现复合搜索条件构建” 提供工具类,方便地构造 Condition ,或者将业务方自定义的 pojo 业务对象,转换成 Condition 。 这样,兼顾灵活性和友好性。唯一的不足是,让使用方多写了一个方法调用。
清单六:
@Data public class ExportParam { /** 调用方,必传 */ private String source; /** 导出业务类型,必传 */ private String bizType; /** 搜索参数,必传 */ private Condition search; /** 请求ID,必传 */ private String requestId; /** 导出ID, 运维使用 */ private Long exportId; }这样是不是可以了? 想一想,如果搜索里面有一些必传参数要进行强校验,比如归属(店铺ID),起始时间等,从 Condition 里解析出这些条件可是不容易哦。 最好抽离出来。
清单七:
@Data public class ExportParam { /** 调用方,必传 */ private String source; /** 导出业务类型,必传 */ private String bizType; /** 搜索参数,必传 */ private SearchParam search; /** 请求ID,必传 */ private String requestId; /** 导出ID, 运维使用 */ private Long exportId; } @Data class SearchParam { /** 业务归属ID,必传 */ private Long bizId; /** 搜索起始时间,必传 */ private Long startTime; private Long endTime; /** 扩展搜索入参,可选 */ private Condition condition; }关于通用搜索入参,如果读者有更好的方案,欢迎提出~~
设计选择清单六和清单七的搜索入参设计,哪种更好呢?清单六的方式更加统一,但对必传参数支持不太友好,解析逻辑会比较复杂; 清单七将搜索入参分为了必传和可选,更容易判断,但在形式上不如清单六那么统一,在实现上,也需要将必传参数和 condition 在内部做一个聚合。
我个人会倾向于清单七。
现在,来看订单导出。如何将订单导出纳入到通用导出的范畴内?
退款导出只考虑一种形态,即退款单导出。订单导出可以有多种形态。比如有通用的订单导出,有分销采购单导出;通用的订单导出又有标准报表导出和自定义报表导出,自定义导出有订单维度的导出和商品维度的导出,标准报表是订单与商品的混合维度的导出。看来 bizType 有点不够用了。
考虑通用的订单导出和分销采购单导出。有两种方案:
只使用 bizType : 通用的订单导出用 bizType = 'default_order', 分销采购单导出用 bizType = 'fenxiao_order'。 这样倒无大碍,不过要统计这两种导出时,就要做解析和处理。
使用大类 bizType 和 细分 category 。两者都是 bizType = 'order' ,通用的 category = 'default' , 分销采购单的 category = 'fenxiao' 。这样,无论是合并统计还是区分对待,都更加清晰。
如何区分订单维度和商品维度的导出呢?这个相对容易解决。维度只是一个导出选项。 可以在 ExportParam 增加一个 options:Map 参数, 提供定制化的可以组合的导出选项。导出选项有维度、文件格式等。这些选项参数如果直接放在 ExportParam ,会让这个类变得臃肿。
如何区分标准报表导出和自定义报表导出呢? 标准和自定义是策略。标准和自定义可能是多个导出选项的组合。不适合放在 options 里;同时,标准和自定义可能适用于所有的业务类型和细分类,是一个切面概念。因此设置一个 strategy 参数。 这个 strategy 可以决定一些选项的组合设置。
现在,梳理一下导出分类的几个层面:业务类型 ( order, refund ) - 细分类 (default, fenxiao) - 策略 ( strategy ) - 选项 (options) 。 这些是否足够对所有导出进行分类了。 这也说明了,当一个服务要接入多个业务类型时,需要进行仔细的分类。