背景
为解耦复杂逻辑而生,帮助解耦业务代码,让每一个业务片段都是一个组件.支持规则文件的热加载,即时完成修改生效.
类图概览
设计原则
一.开闭原则
对外扩展开发,对内修改关闭
二.单一职责原则
解释:一个类只负责一项职责。
实现:这里的职责代表一次编排,例如SequenceTicketStageExecutorFlow 代表此次编排的内容,如果符合可以复用,不符合增加新类编排内容。
三.依赖倒置原则
解释:
1.上层模块不应该依赖底层模块,他们都应该依赖于抽象
2.抽象不应该依赖于细节,细节应该依赖于抽象
实现:执行流程面向接口(TicketExecutorFlow)。节点处理面向接口(TicketStage)。
四.里氏替换原则
解释:子类不应该覆盖覆盖父类的方法
实现:SequenceTicketStageExecutorFlow 没有覆盖 TicketStageExecutorFlow的execute方法,覆盖的方法在父类中都是抽象方法。
五.最少知道原则
解释:降低类之间的耦合性,提高代码的复用性
使用指南
xml配置形式
flowConfig.xml 总配置,配置多种类型编排逻辑
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="classpath:/flow/TicketSequenceConfig.xml" />
</beans>
TicketSequenceConfig.xml 具体编排内容
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath*:/common/beans.xml"/>
<bean id="ticketDetailExecutorFlow" class="com.idanchuang.customer.satisfaction.data.manager.flow.SequenceTicketStageExecutorFlow">
<property name="bizCheckStageList">
<list>
<ref bean="ticketDetailParamsCheckStage" />
</list>
</property>
</bean>
注解配置方式
flowConfig.properties 配置属性
#demo
ticket.detail.get.detailCheckList = ticketDetailParamsCheckStage
ticket.detail.get.detailBizList = ticketDetailApplyInfoStage,ticketDetailAddressStage
config/TicketGetConfig.java 配置代码
@Configuration
@PropertySource(value={"classpath:/flowConfig.properties"})
public class TicketGetConfig {
@Value("#{'${ticket.detail.get.detailCheckList}'.split(',')}")
private List<String> detailCheckList;
@Value("#{'${ticket.detail.get.detailBizList}'.split(',')}")
private List<String> detailBizList;
@Resource
private ApplicationContext applicationContext;
@Bean(name = "ticketDetail")
public SequenceTicketStageExecutorFlow ticketDetail() {
SequenceTicketStageExecutorFlow sequenceTicketStageExecutorFlow = new SequenceTicketStageExecutorFlow();
sequenceTicketStageExecutorFlow.setBizCheckStageList(convertTicketStage(detailCheckList));
sequenceTicketStageExecutorFlow.setResultStageList(convertTicketStage(detailBizList));
return sequenceTicketStageExecutorFlow;
}
@Bean(name = "ticketBriefDetail")
public SequenceTicketStageExecutorFlow ticketBriefDetail() {
SequenceTicketStageExecutorFlow sequenceTicketStageExecutorFlow = new SequenceTicketStageExecutorFlow();
sequenceTicketStageExecutorFlow.setResultStageList(convertTicketStage(detailBizList));
return sequenceTicketStageExecutorFlow;
}
private List<TicketStage> convertTicketStage(List<String> ticketStage) {
List<TicketStage> result = new ArrayList<>();
if (CollectionUtils.isEmpty(ticketStage)) {
return result;
}
ticketStage.forEach(stageName -> {
TicketStage tmpStage = applicationContext.getBean(stageName, TicketStage.class);
result.add(tmpStage);
});
return result;
}
}
单元测试
@RunWith(SpringRunner.class)
@SpringBootTest(classes = DataApplication.class)
public class SequenceTest {
@Resource(name = "ticketDetail")
private TicketStageExecutorFlow<TicketDetailFlowParam, TicketeDetailFlowResult, TicketDetailFlowContext> ticketDetail;
@Resource(name = "ticketBriefDetail")
private TicketStageExecutorFlow<TicketDetailFlowParam, TicketeDetailFlowResult, TicketDetailFlowContext> ticketBriefDetail;
@Resource(name = "ticketDetailExecutorFlow")
private TicketStageExecutorFlow<TicketDetailFlowParam, TicketeDetailFlowResult, TicketDetailFlowContext> ticketDetailExecutorFlow;
@Test
public void testA() {
TicketDetailFlowParam ticketDetailFlowParam = new TicketDetailFlowParam();
ticketDetailFlowParam.setId(12L);
ticketDetail.execute(ticketDetailFlowParam);
ticketBriefDetail.execute(ticketDetailFlowParam);
ticketDetailExecutorFlow.execute(ticketDetailFlowParam);
}
}