目录
背景
流程梳理
技术预研
关键点代码
后记
背景
产品贱兮兮的跑来问:“星哥,我们既然接入了那么多渠道,那么能不能在客户下单的时候做多渠道比价了?”
我:“这是什么骚操作?”
产品:“就是客户下单的时候,我们可以在已经接入的渠道中进行比价,然后选择最便宜的渠道去下单!”
我非常差异:“这样做,能节省多少成本?”
产品:“说出来你可能不信,平均每单能节约1块钱”
我:“然后了?1天能节约几百块钱?”
产品:“是的!boss要求做的!”
我目瞪口呆!
流程梳理
公司最近接入了一大票的渠道商,这些渠道商针对某一个产品提供了统一的产品编码不同的价格,客户在公司所属平台下单,公司可以自行消化或者走不同的渠道商进行比价,然后找最便宜的渠道商下单,不同渠道商的价格大致一致,但是存在少量差异,并且这种差异是实时的,所以需要在客户下单时进行实时比价,然后下单,大致流程如下:
技术预研
1:客户下单之后需要到第三方渠道商处进行比价,时间不可控,而客户需要知道下单结果(这一点跟其他平台的不同,因为我们这个行业的产品价格属于实时价格,客户下单支付的价格,很可能下一刻就发生了变化,如果价格变高,那么平台就会存在亏本情况),所以可以参考作者的另一篇设计(基于rockermq的异步服务)
2:渠道商有十几个,虽然每个渠道商的产品编码一致,但是调用的接口是五花八门,有http、https、webserver,而且每个渠道商的协议,通信加密方式都不一样,需要抽象出统一的接口进行管理,设计模式就派上用场啦!
3:多渠道比价,需要尽量在更多的渠道商处进行比价,java多线程的Callable在配合ExecutorService,即可实现!
4:用户体验,多渠道进行比价的同时,也要考虑用户体验问题,所以比价的时间不能太长,根据作者统计,调用渠道商接口的超时时间设置在3s
5:成本问题,由于价格属于实时价格,那么在选出最优价格的同时,需要在对应渠道商处进行下单,并且只有下单成功,才可以返回客户下单成功
6:业务闭环,下单失败?如果下单的时候该渠道商价格发生变化,需要做出决策如何处理?作者这里针对下单失败,直接就是本平台消化,不再进行比价
关键点代码
针对多渠道商统一接口管理
public abstract class SupplierInterface {
/**
* 根据产品信息查询对应产品实时价格
* @param queryProductPriceReq 产品信息
* @return QueryProductPriceRsp 查询价格结果
*/
public abstract QueryProductPriceRsp queryProductPrice(QueryProductPriceReq queryProductPriceReq);
}
@Service
public class SupplierJingDongInterface extends SupplerInterface {
@Override
public QueryProductPriceRsp queryProductPrice(QueryProductPriceReq queryProductPriceReq) {
// 具体渠道商调用接口实现
return null;
}
}
@Service
public class SupplierTaoBaoInterface extends SupplerInterface {
@Override
public QueryProductPriceRsp queryProductPrice(QueryProductPriceReq queryProductPriceReq) {
// 具体渠道商调用接口实现
return null;
}
}
针对多渠道比价
public class SupplierQueryProductPriceTask implements Callable<QueryProductPriceRsp> {
SupplierInterface supplierInterface;
QueryProductPriceReq queryProductPriceReq;
public void SupplierTask(SupplierInterface supplierInterface,
QueryProductPriceReq queryProductPriceReq) {
this.supplierInterface = supplierInterface;
this.queryProductPriceReq = queryProductPriceReq;
}
@Override
public QueryProductPriceRsp call() {
return supplierInterface.queryProductPrice(queryProductPriceReq);
}
}
public class Test {
public static void main(String[] args) {
ExecutorService executor = Executors.newCachedThreadPool();
QueryProductPriceReq queryProductPriceReq = new QueryProductPriceReq();
SupplierInterface supplierJingDongInterface = new SupplierJingDongInterface();
SupplierInterface supplierTaoBaoInterface = new SupplierTaoBaoInterface();
SupplierQueryProductPriceTask supplierJingDongTask = new SupplierQueryProductPriceTask(supplierJingDongInterface,queryProductPriceReq);
SupplierQueryProductPriceTask supplierTaoBaoTask = new SupplierQueryProductPriceTask(supplierTaoBaoInterface,queryProductPriceReq);
Future<QueryProductPriceRsp> jingDongTaskResult = executor.submit(supplierJingDongTask);
Future<QueryProductPriceRsp> taoBaoTaskResult = executor.submit(supplierTaoBaoTask);
executor.shutdown();
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
System.out.println("京东价格:" + jingDongTaskResult.get());
System.out.println("淘宝价格:" + taoBaoTaskResult.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
以上代码均为标识流程的伪代码,无法进行正常运行,渠道商也没有淘宝和京东只是作者举例而已!
后记
针针对不同的业务场景进行设计,大多数的场景其实已经存在完整的解决方案,攻城狮们其实更多需要考虑的是业务完整性和闭环问题,比如作者这里并没有展示关于退单问题的设计,另外线程池这块需要控制,针对具体业务场景进行设置,不然比价线程开的过多,消耗太大,服务会变得不可用!