在一次需求开发中,需要给10多个接口添加一个公共字段。并在交易入口处添加统一的校验逻辑。我审视了下现有的接口设计,突然感觉无从下手,也不是没法改,只是在现在的设计上改起来会很丑。以前单个接口加字段时,不觉得有啥问题,现在突然觉得原来设计,扩展性还是有点欠缺。
业务背景
收单支付业务,提供支付【/order/pay】,订单查询【/order/orderQuery】,退款【/order/refund】,退款查询【/order/refundQuery】等服务。
原代码设计
所有交易从一个入口进来
/*----顶层设计----*/
/** 请求参数-父类*/
public class BaseParam{
/** 请求IP */
String ip;
/** 交易流水号 */
String seqNo;
}
/** 响应结果-父类 */
public class BaseResult{
/** 响应码 */
String resultCode;
/** 响应描述信息 */
String resultMsg;
/** 交易流水号 */
String seqNo;
}
/**
* 业务处理接口
*/
public interface BaseHandle <R extends BaseResult, P extends BaseParam> {
/** 接口名称 */
@NotBlank
String getHandleName();
/** 业务逻辑 */
R execute(P param);
}
/*---- 支付接口设计 ----*/
/**
* 支付接口请求参数
*/
public class PayParam extends BaseParam {
private String orderId;
private String tradeTime;
private String tradeAmount;
/** 用途 */
private String remark;
/* 其他字段...... */
}
/**
* 支付接口响应结果
*/
public class PayResult extends BaseResult {
private String orderId;
private String status;
private String succTime;
/* 其他字段...... */
}
/**
* 支付接口处理器
*/
public class PayHandler implements BaseHandler<PayResult, PayParam> {
@Override
@NotBlank
public String handlerName() {
return "pay";
}
@Override
public OrderPayResult execute(PayParam param) {
OrderPayResult result = new OrderPayResult();
/* 业务处理逻辑 ....*/
return result;
}
}
/**
* 支付接口处理器
*/
@Slf4j
@RestController
@RequestMapping("/trade")
public class UnifyTradeController {
@Resource
private List<BaseHandler> handlers;
private ConcurrentHashMap<String, Optional<BaseHandler>> handlerMap = new ConcurrentHashMap<>();
@PostMapping(value = "/order/{handlerName}", consumes = {MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE})
@PublicApi
public BaseResult execute(HttpServletRequest request, @PathVariable("handlerName") String handlerName) {
BaseParam param = null;
BaseResult result = null;
Optional<BaseHandler> handlerOptional = handlerMap.getOrDefault(handlerName, Optional.empty());
if (!handlerOptional.isPresent()) {
for (BaseHandler handler : handlers) {
if (handler.handlerName().equals(handlerName)) {
handlerOptional = Optional.of(handler);
handlerMap.putIfAbsent(handlerName, handlerOptional);
break;
}
}
}
if (handlerOptional.isPresent()) {
Class<?> aClass = handlerOptional.get().getClass();
ParameterizedTypeImpl parameterizedType = (ParameterizedTypeImpl) aClass.getGenericInterfaces()[0];
Type type = parameterizedType.getActualTypeArguments()[1];
JavaType javaType = typeFactory.constructType(type);
String bodyContent = Util.toString(request.getReader());
param = objectMapper.readValue(bodyContent, javaType);
check(param)
Method method = aClass.getMethod("execute", BaseParam.class);
result = (BaseResult) method.invoke(handlerOptional.get(), param);
}
return result;
}
/**
* 基础参数校验
*/
private void check(BaseParam param){
/* 校验逻辑 */
}
}
问题
现在给部分接口添加同一个字段,然后这个字段需要做一些业务逻辑校验。想做的就是在公共入口把这块校验逻辑给处理了。
-
方案一:新增字段直接加在【BaseParam】,但是这样实际就变相给其他接口也加了这个字段。每次都这么干的话,后面维护就很艰难了。
-
方案二:新建一个中间类【NewBaseParam】,这个类的属性,新增要加的字段,再继承【BaseParam】。再让【PayParam】继承【NewBaseParam】。在check()这边可以根据【handleName】,进行强转,然后拿到新增的属性,进行逻辑校验。
-
方案三:在【BaseHandler】和实际业务处理器【PayHandler】之间,加个抽象类。核心思想就是在抽象类里面做公共的检测,同时保留一个可以给子类重写的检测逻辑,这块做了一会思考,试了好几次不知道怎么加。这块需要修改整块的架构,改动还是挺大的。
最合适的还是方案三,方案二是治标不治本