在项目中,对于单据的扩展是基于类似于接口扩展实现的。从业务横行来看,业务有A、B、C;从纵向来看,单个业务逻辑编排也可以划分为基础数据查询,决策判断,逻辑执行三大块。
单据扩展:平台构建单据基本信息,不同业务往单据中构建不同的信息。
将业务玩法+业务逻辑抽象可得策略模式和模版方法模式思维,可将二者通过Spring的加载机制链接在一起共同实现代码的高内聚,低耦合的特性。
业务上下文
public class BusinessContext {
private String type;
private Map<String , String> features;
}
1、抽象业务逻辑编排并且定位为接口,为策略模式提供基础
public interface BusinessStrategy {
/**
* desc: 查询节点:查询决策节点所需的数据
*/
Object query(BusinessContext businessContext);
/**
* desc: 决策节点:通过传入的业务上下文进行判断
*/
boolean isHandle(Object query);
/**
* desc: 业务逻辑具体执行节点
*/
void handle(BusinessContext businessContext ,Object query , Map<String, String> orderFeature);
/**
* desc: 策略管理类调用节点1
*/
default void execute(BusinessContext businessContext , Map<String, String> orderFeature) {
Object query = query(businessContext);
boolean handleFlag = isHandle(businessContext);
if (handleFlag) {
handle(businessContext, query , orderFeature);
}
}
}
2、策略模式管理类和扩展入口
public class BusinessStrategyManager {
@Resource
private List<BusinessStrategy> strategyList;
public Map<String, String> doExecute(BusinessContext businessContext){
Map<String, String> res = new HashMap<>();
for (BusinessStrategy businessStrategy : strategyList) {
//循环调用不同的实现
businessStrategy.execute(businessContext , res);
if (MapUtils.isNotEmpty(res)) {
break;
}
}
return res;
}
}
3、A业务实现(如果有其他实现,followA实现即可,不需要关心具体的bundle调用)
public class BusinessStrategyAImpl implements BusinessStrategy {
@Override
public Object query(BusinessContext businessContext) {
return "查询用来判断的数据";
}
/**
* desc: 决策节点:通过传入的业务上下文进行判断
*
* @param query
*/
@Override
public boolean isHandle(Object query) {
System.out.println("判断的数据进行判断");
return true;
}
/**
* desc: 业务逻辑具体执行节点
*
* @param businessContext
* @param query
* @param orderFeature
*/
@Override
public void handle(BusinessContext businessContext, Object query, Map<String, String> orderFeature) {
System.out.println("业务逻辑执行");
orderFeature.put("A" , "BusinessStrategyAImpl");
}
}
在策略模式管理类和扩展入口,最初的运行版本对于businessStrategy.execute()方法的异常是自己捕获的,并没有往外抛出,导致了单据未补充正确的信息,但是单据正常的创建了,以至于后续链路全部异常。
从业务视角下看,单据扩展信息补充发生异常时,应当阻断单据创建。从扩展框架的视角上看,实现类的异常应当直接抛出,不能被框架消化,否侧会导致使用者无法定位问题和发生预期之外的异常
该框架在线上运行过程中,虽然无异常问题,但是从代码层面来看,依然具有优化的空间。
通用的策略框架适用于调用方法清楚的知道需要调用那个策略类,调用方直接指定策略类,但是在当前扩展中,调用方也不知道具体调用策略类,需要业务实现类中查询数据之后再进行判断,对指定策略类的步骤进行了后置,导致通用策略类框架不适用于当前情况。
如果有n个实现类,最差的情况需要把前面的n-1个实现类执行完成之后,才会执行到第n个实现类。
?业务上下文
public class BusinessContext {
private String type;
private Map<String , String> features;
}
1、抽象业务逻辑编排并且定位为接口,为策略模式提供基础
public interface BusinessStrategy2 {
/**
* desc: 决策节点
*/
boolean isHandle(BusinessContext businessContext);
/**
* desc: 业务逻辑具体执行节点
*/
void handle(BusinessContext businessContext, Map<String, String> orderFeature);
/**
* desc: 策略管理类调用节点2
*/
default void execute2(BusinessContext businessContext , Object query, Map<String, String> orderFeature) {
boolean handleFlag = isHandle(businessContext);
if (handleFlag) {
handle(businessContext, orderFeature);
}
}
}
2、策略模式管理类和扩展入口
public class BusinessStrategyManager2 {
@Resource
private List<BusinessStrategy2> strategyList;
private Map<String, List<BusinessStrategy2>> strategyMap = new HashMap<>();
//配置项:配置业务实例和所需查询结果
private Map<String, String> strategyGroupMap = new HashMap() {{
put("A", "orderA");
put("A1", "orderA");
put("A2", "orderA");
put("B", "orderB");
put("B1", "orderB");
put("B2", "orderB");
}};
//配置项:配置所需查询结果和查询对应的实例全类名
private Map<String, String> queryGroupMap = new HashMap() {{
put("orderA", "com.example.testproject.design.strategy.update.impl.QueryOrderAImpl");
put("orderB", "com.example.testproject.design.strategy.update.impl.QueryOrderBImpl");
}};
@PostConstruct
public void buildStrategyMap() {
//对业务实例根据所需查询结果进行分组
for (BusinessStrategy2 strategy : strategyList) {
if (strategyGroupMap.containsKey(strategy.getClass().getName())) {
List<BusinessStrategy2> list = strategyMap.get(strategyGroupMap.get(strategy.getClass().getName()));
if (Objects.isNull(list)) {
list = new ArrayList<>();
}
list.add(strategy);
strategyMap.put(strategyGroupMap.get(strategy.getClass().getName()), list);
}
}
}
public Map<String, String> doExecute(BusinessContext businessContext) {
Map<String, String> res = new HashMap<>();
for (Map.Entry<String, List<BusinessStrategy2>> stringListEntry : strategyMap.entrySet()) {
//不同所需查询结果的组,获取不同的查询实例进行查询
if (queryGroupMap.containsKey(stringListEntry.getKey())) {
//获取配置的查询实例全类名
String className = queryGroupMap.get(stringListEntry.getKey());
//获取实例
QueryOrderInter queryOrderInter = SpringUtils.getBean(className, QueryOrderInter.class);
if (Objects.isNull(queryOrderInter)){
throw new RuntimeException("未找到对应的查询实例,className={}" + className);
}
Object query = queryOrderInter.query(businessContext);
List<BusinessStrategy2> value = stringListEntry.getValue();
//所需查询结果的相同的组对查询结果进行消费
for (BusinessStrategy2 strategy : value) {
strategy.execute2(businessContext, query, res);
if (MapUtils.isNotEmpty(res)) {
break;
}
}
}
}
return res;
}
}
3、查询抽象接口
public interface QueryOrderInter {
Object query(BusinessContext businessContext);
}
4、查询orderA
public class QueryOrderAImpl implements QueryOrderInter {
@Override
public Object query(BusinessContext businessContext) {
System.out.println("查询orderA");
return "orderA";
}
}