@(工作) ####介绍 项目系统间是通过接口进行业务调用,业务目前分B2C和C2C两种交易模式,不同游戏在相同或者不同的交易模式下,校验、支付、商品交互、发货等业务处理也不一样。这就形成相同场景下不同的业务处理需求。重构前的代码部分采用了工厂模式和抽象工厂方法,但是由于抽象工厂方法的原因导致结构设计特别冗余,编码起来特别繁琐,修改起来更麻烦。重构前还有一个不好的地方是B2C和C2C的校验是放一块的,通过交易模式来划分,但是如果不同游戏的校验不一样的话,很难扩展。
重构后的设计是,按业务划分,通过交易模式和游戏类别来生成相关的交易业务Service,将相同的业务方法写到抽象父类的方法中,抽象父类对外只暴露业务接口方法,这样保证了业务入口的一致性,防止业务方法被部分调用的错误。不同游戏、不同模式的业务方法写到相关的子类中,保证业务方法的特殊性。 拿下单校验举例,代码如下:
public class TradeFactory {
public static TradeValidateService getTradeValidteFactory(int tradeMode, int gameId) {
if (TradeConstants.B2C_MODE == tradeMode) {
if (gameId == 16) {
return SpringContextHolder.getBean(B2CTradeValidateService.class);
} else {
return SpringContextHolder.getBean(B2CTradeValidateService.class);
}
}
if (TradeConstants.C2C_MODE == tradeMode) {
if (gameId == 16) {
return SpringContextHolder.getBean(C2CTradeValidateService.class);
} else {
return SpringContextHolder.getBean(C2CTradeValidateService.class);
}
}
throw new RuntimeException("invalid tradeMode: " + tradeMode);
}
注: 根据交易模式和游戏类别来生成业务处理相关的Service
@Service
public abstract class TradeValidateService {
// 校验入口,让子类去实现
public abstract boolean validateBuyer(int platformId, int gameId, String goodsCode,
long buyerUserId, String buyerOpenId, String sellerOpenId, int goodsType);
// 共同的校验,写到父类,方便子类们的调用
protected boolean isInSingleGoodsLimit(int platformId, int gameId,
String buyerOpenId, String goodsCode) {
return buyerOrderCache.isInThisGoodsBuyLimitTime(platformId, gameId, buyerOpenId, goodsCode);
}
…
注:抽象的父类对外只暴露一个入口;将校验拆成原子方法,让子类去选择需要的方法进行校验。
@Service
public class C2CTradeValidateService extends TradeValidateService {
@Override
public boolean validateBuyer(int platformId, int gameId, String goodsCode, long buyerUserId, String buyerOpenId, String sellerOpenId, int goodsType) {
// 此商品是否在其下单限制内
if (isInSingleGoodsLimit(platformId, gameId, buyerOpenId, goodsCode)) {
throw new OrderException(OrderResultCode.BUYER_CANCELED_ORDER_IN_LIMIT_TIME, null, null);
}
…….
}
// 特有方法,子类实现
protected boolean isC2CSystemClose(Integer platformId, Integer gameId) {
….
}
}
注: 子类去实现父类的抽象的入口方法,自身特有的校验,子类本身去实现。
以上设置增加了业务扩展性,而且保证了入口一致性。缺点是如果新增一种交易模式,开发量比较大,要将交易流程整个都要重写一下。针对此问题,下一步的解决方式是将业务原子化,即下单、支付、发货等接口做成不可拆分的模块,然各个子类选择相关原子模块进行组装,实现业务处理。