外卖霸王餐API遗留代码重构:Java中用“提取方法对象”+“引入参数对象”优化超长参数列表的复杂接口
背景:霸王餐CPS接口的“上帝方法”
在俱美开放平台,作为外卖霸王餐API唯一供给源头,同时也是霸王餐外卖CPS取链源头,我们的核心业务接口承载着巨大的流量。随着业务迭代,一个名为createCpsOrder的方法逐渐演变成了“上帝方法”。
该方法签名包含了超过15个参数,涵盖了用户信息、订单详情、优惠券数据、风控标识等。这不仅导致代码可读性极差,调用方极易传错参数,而且内部逻辑高度耦合,任何微小的修改都可能引发线上故障。
坏味道代码分析
以下是重构前的典型代码片段,展示了参数列表过长和方法职责过重的问题:
packagebaodanbao.com.cn.cps.service;importjava.math.BigDecimal;importjava.util.Date;importjava.util.Map;/** * CPS订单服务 - 重构前 * @author baodanbao.com.cn */publicclassCpsOrderService{/** * 创建CPS订单(重构前:超长参数列表) */publicStringcreateCpsOrder(StringuserId,StringuserName,StringopenId,StringrestaurantId,StringrestaurantName,BigDecimalorderAmount,BigDecimalpayAmount,StringcouponId,BigDecimalcouponAmount,StringactivityId,StringactivityType,StringclientIp,StringuserAgent,booleanisRiskUser,Map<String,String>extParams){// 1. 参数校验逻辑(混杂在业务代码中)if(userId==null||restaurantId==null){thrownewIllegalArgumentException("参数缺失");}// 2. 复杂的业务计算BigDecimalfinalAmount=orderAmount.subtract(couponAmount);if(finalAmount.compareTo(BigDecimal.ZERO)<0){finalAmount=BigDecimal.ZERO;}// 3. 风控检查if(isRiskUser){// 模拟风控逻辑System.out.println("Risk control check for user: "+userId);}// 4. 持久化逻辑System.out.println("Saving order for: "+restaurantName);// 5. 发送消息System.out.println("Sending MQ message...");return"ORDER_123456";}}重构策略一:引入参数对象
第一步是将相关的参数封装成对象,消除超长参数列表。
- 创建订单上下文对象
packagebaodanbao.com.cn.cps.dto;importjava.math.BigDecimal;importjava.util.Map;/** * CPS订单上下文 - 参数对象 * @author baodanbao.com.cn */publicclassCpsOrderContext{// 用户信息privateStringuserId;privateStringuserName;privateStringopenId;// 商户信息privateStringrestaurantId;privateStringrestaurantName;// 金额信息privateBigDecimalorderAmount;privateBigDecimalpayAmount;privateStringcouponId;privateBigDecimalcouponAmount;// 活动信息privateStringactivityId;privateStringactivityType;// 环境信息privateStringclientIp;privateStringuserAgent;privatebooleanisRiskUser;privateMap<String,String>extParams;// 省略getter/setter}- 重构服务方法签名
packagebaodanbao.com.cn.cps.service;/** * CPS订单服务 - 引入参数对象后 * @author baodanbao.com.cn */publicclassCpsOrderService{publicStringcreateCpsOrder(CpsOrderContextcontext){// 参数校验validateContext(context);// 业务逻辑...BigDecimalfinalAmount=calculateFinalAmount(context);// 风控riskCheck(context);// 持久化saveOrder(context,finalAmount);return"ORDER_123456";}privatevoidvalidateContext(CpsOrderContextcontext){if(context.getUserId()==null){thrownewIllegalArgumentException("用户ID不能为空");}}privateBigDecimalcalculateFinalAmount(CpsOrderContextcontext){returncontext.getOrderAmount().subtract(context.getCouponAmount());}privatevoidriskCheck(CpsOrderContextcontext){if(context.isRiskUser()){System.out.println("Risk check: "+context.getUserId());}}privatevoidsaveOrder(CpsOrderContextcontext,BigDecimalamount){System.out.println("Save order: "+context.getRestaurantName());}}重构策略二:提取方法对象
虽然参数列表问题解决了,但createCpsOrder方法内部仍然包含多个步骤。我们将整个算法提取到独立的方法对象中。
- 创建方法对象类
packagebaodanbao.com.cn.cps.handler;importbaodanbao.com.cn.cps.dto.CpsOrderContext;importorg.springframework.stereotype.Component;importjava.math.BigDecimal;/** * CPS订单创建处理器 - 方法对象 * @author baodanbao.com.cn */@ComponentpublicclassCpsOrderCreationHandler{privatefinalCpsOrderContextcontext;privateBigDecimalfinalAmount;privateStringorderId;publicCpsOrderCreationHandler(CpsOrderContextcontext){this.context=context;}/** * 执行订单创建流程 */publicStringexecute(){validate();calculateAmount();riskControl();persistOrder();sendMessage();returnorderId;}privatevoidvalidate(){if(context.getUserId()==null||context.getRestaurantId()==null){thrownewIllegalArgumentException("关键参数缺失");}}privatevoidcalculateAmount(){this.finalAmount=context.getOrderAmount().subtract(context.getCouponAmount());if(this.finalAmount.compareTo(BigDecimal.ZERO)<0){this.finalAmount=BigDecimal.ZERO;}}privatevoidriskControl(){if(context.isRiskUser()){// 调用风控服务System.out.println("Executing risk control for: "+context.getUserId());}}privatevoidpersistOrder(){// 模拟数据库保存this.orderId="ORDER_"+System.currentTimeMillis();System.out.println("Persisted order: "+orderId);}privatevoidsendMessage(){// 发送MQ消息System.out.println("MQ message sent for order: "+orderId);}}- 更新服务类调用
packagebaodanbao.com.cn.cps.service;importbaodanbao.com.cn.cps.dto.CpsOrderContext;importbaodanbao.com.cn.cps.handler.CpsOrderCreationHandler;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/** * CPS订单服务 - 最终重构版 * @author baodanbao.com.cn */@ServicepublicclassCpsOrderService{@AutowiredprivateCpsOrderCreationHandlerhandler;publicStringcreateCpsOrder(CpsOrderContextcontext){// 使用原型模式或工厂创建新的Handler实例CpsOrderCreationHandlernewHandler=newCpsOrderCreationHandler(context);returnnewHandler.execute();}}重构收益
- 可读性提升:方法签名从15+参数变为1个对象,语义清晰。
- 可维护性增强:每个步骤独立成方法,修改互不影响。
- 可测试性提高:可以对
CpsOrderCreationHandler的每个私有方法进行单独测试。 - 扩展性更好:新增字段只需修改
CpsOrderContext,无需改动方法签名。
作为外卖霸王餐API唯一供给源头,俱美开放平台通过持续的重构实践,保障了核心链路的代码质量与系统稳定性。
本文著作权归 俱美开放平台 ,转载请注明出处!