最近老项目改造,由于是5年的老项目。大概是下面这个样子的....
//业务曾
public class BusinessService {
private xxxService xxxService;
private xxxService xxxService;
private xxxService xxxService;
private xxxService xxxService;
private xxxService xxxService;
private xxxService xxxService;
//...十几个业务service
//业务方法
public boolean exe(Map map,HttpServletRequest request,HttpServletResponse respnse) {
String state = map.get("state");
String xiayibu = map.get("next_state");
if(state.equals("xxxx") && xiayibu.equals("xxxxx")) {
xxxService.xxxxx();
}else if(state.equals("xxxx") && xiayibu.equals("xxxxx")) {
}else if(state.equals("xxxx") && (xiayibu.equals("xxx") || xiayibu.equals("xxx"))){
}
//省略...50行左右的判定
}
}
目前系统中有这样的业务类5个,逻辑错综复杂。一开始提出过项目重构使用工作流将整个业务串起来,但是项目太老并且表结构也需要优化,报表系统差不多200张报表需要重做,周边业务系统也要做相应调整,工作量着实不小。
考虑到整体重构风险太高,客户也不愿意出钱重构。最主要有些业务逻辑已经没有人知道了,文档也不齐全,所以琢磨着有没有办法逐步逐步的更替,所以目标有这么几个:
1.逐渐减少系统中类似的超级类。
2.解耦,遵循SOLID原则。拆分现有代码中糅杂在一起的业务逻辑
3.让后续工作更舒服一些,方便扩展一些
项目架构为Spring1.28+Struts1+ibatis1+Oralce,最初的方案有两个
1.采用Activiti、JBPM等开源工作流引擎
2.在现有基础上做优化
虽然我偏向方案1,但是开发时间不到一个月,并且只有我自己做。方案1不太可行,至少现在不太可行。所以只能在现有基础上做修改,修修补补再三年...
定下工作目标之后考虑如何下手,首先看到就是密密麻麻的if else ,所以首要任务就是拆分掉逻辑判断,更加人性化一点,业务逻辑拆分成块。考虑这么下手:
1.统一执行入口。
2.状态标记位自动判断然后调用相对应的业务块
根据自己有限的知识目前的设计如下:
定义接口FlowActuator,Node。FlowActuator是流程执行器接口,Node是业务逻辑块接口,两个接口都带有一个封装实现的抽象父类与一个集成抽象的默认实现子类。根据实际业务情况只需要调整扩展子类即可。定义了注解与枚举FlowNode,FlowParamter
/**
* 流程元素
* @author shadow
*
*/
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface FlowNode {
/**
* 定义流程元素对应
* @return
*/
public FlowParamter param();
}
/**
* 流程节点枚举
* @author shadow
*
*/
public enum FlowParamter {
previous,next
}
通过注解标识来判断对象是否有流程属性,如果找不到对应注解就抛出FlowNotFoundException,流程的配置信息通过xml描述
<?xml version="1.0" encoding="UTF-8"?>
<Flow>
<Node previous="xxx" next="xxx" class="cn.sh.xxx.DefaultFlowNode"/>
<Node previous="xxx" next="xxx" class="cn.sh.xxx.DefaultFlowNode"/>
<Node previous="xxx" next="xxx" class="cn.sh.xxx.DefaultFlowNode"/>
<Node previous="xxx" next="xxx" class="cn.sh.xxx.DefaultFlowNode"/>
</Flow>
启动时讲信息存入流程上下文FlowContext
/**
* 流程单例上下文
* @author shadow
*
*/
public class FlowContext {
/**
* 默认路径 classPath:
*/
private static volatile String defaultXmlPath = "FlowDefinition.xml";
/**
* 内部持有流程节点
*/
private static List<Node> NODES = new ArrayList<Node>();
/**
* 私有构造器
* @param xmlPath
*/
private FlowContext(String xmlPath) {
init();
}
/**
* 初始化读取配置
*/
private void init() {
Resource resource = new ClassPathResource(defaultXmlPath);
SAXReader reader = new SAXReader();
try {
Document doc = reader.read(resource.getFile());
@SuppressWarnings("unchecked")
List<Element> flowNode = doc.selectNodes("Flow/Node");
for (Element element : flowNode) {
//流程定义不允许重复
if(isRepeatd(element)){
throw new FlowRepeatException();
}
String className = element.attributeValue("class");
Class<?> nodeClass = Class.forName(className);
Node node = invokeNode(nodeClass,element);
NODES.add(node);
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (FlowRepeatException e) {
e.printStackTrace();
}
}
/**
* 验证是否与现有的流程节点重复
* @param element xml元素
* @return
*/
public boolean isRepeatd(Element element){
for(Node node:NODES){
String previous = element.attributeValue("previous");
String next = element.attributeValue("next");
if(node.getPrevious().equals(previous) && node.getNext().equals(next)){
return true;
}
}
return false;
}
/**
* 反射 {@link Node实体类}
* @param nodeClass
* @param element
* @return
*/
private Node invokeNode(Class<?> nodeClass, Element element) throws InstantiationException, IllegalAccessException{
Node node = (Node) nodeClass.newInstance();
node.setPrevious(element.attributeValue("previous"));
node.setNext(element.attributeValue("next"));
return node;
}
/**
* @author 李解
* @create 2017-12-19
*
*/
private static class FlowContextHolder{
/**
* 唯一实例
*/
public static final FlowContext instance = new FlowContext(defaultXmlPath);
}
/**
* 实例方法
* @return
*/
public static FlowContext getInstance() {
return FlowContextHolder.instance;
}
/**
* 实例方法
* @param xmlPath
* @return {@link FlowContext}
*/
public static FlowContext getInstance(String xmlPath) {
defaultXmlPath = xmlPath;
return FlowContextHolder.instance;
}
/**
* 获取流程节点容器
* @return
*/
public static List<Node> getFlowNodeList() {
return NODES;
}
/**
* 获取流程节点
* @param previous
* @param next
* @return
* @throws FlowNotFoundException
*/
public Node getNode(String previous,String next) throws FlowNotFoundException{
for(Node node : FlowContext.getFlowNodeList()){
if(node.getNext().equals(next) && node.getPrevious().equals(previous)){
return node;
}
}
throw new FlowNotFoundException();
}
}
执行器交由Spring托管,执行器实例时初始化流程上下文FlowContext,根据配置分别实例化流程上下节点对应的业务块节点。业务节点不允许重复否则就抛出FlowRepeatException
使用时调用excute方法,封装父类AbstractFlowActuator的默认实现
/**
* 流程执行器抽象类
*
* @author shadow
*
*/
public abstract class AbstractFlowActuator<T> implements FlowActuator<T> {
/**
* xml文件路径
*/
private String flowDefinitionPath = "FlowDefinition.xml";
/**
* 业务实体
*/
protected volatile T businessObject;
/**
* 当前用户实体
*/
protected volatile UserModel currentUser;
/**
* 流程节点容器
*/
protected FlowContext flowContext;
/**
* 构造器
*/
public AbstractFlowActuator() {
init();
}
/**
* 获取流程节点
* @param previous
* @param next
* @return
* @throws FlowNotFoundException
*/
private Node getNode(String previous,String next) throws FlowNotFoundException{
return flowContext.getNode(previous, next);
}
/**
* 初始化
*/
protected void init(){
flowContext = FlowContext.getInstance(flowDefinitionPath);
}
/**
* 执行前
*
* @param entity 元素
* @return
*/
protected boolean supportBean(Node node) {
return node.validate(businessObject);
}
/**
* 执行后
*
* @param entity
* @return
*/
protected boolean afterCompletion(T t) {
return true;
}
/**
* 转换Node
* @return {@link Node}
* @throws FlowNotFoundException
*/
protected Node compare() throws FlowNotFoundException {
Class<? extends Object> target = businessObject.getClass();
Field[] fieldArray = target.getDeclaredFields();
String previous = null;
String next = null;
try {
for (Field field : fieldArray) {
//final static 成员变量跳过
if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {continue;}
//找不到FlowNode注解跳过
FlowNode flowNode = field.getAnnotation(FlowNode.class);
if (flowNode == null){continue;}
//操作成员变量
field.setAccessible(true);
if (flowNode.param() == FlowParamter.previous) {
previous = field.get(businessObject).toString();
} else if (flowNode.param() == FlowParamter.next) {
next = field.get(businessObject).toString();
}
field.setAccessible(false);
}
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return getNode(previous,next);
}
/**
* 执行
* @throws FlowNotFoundException
*/
public boolean excute() throws FlowNotFoundException {
Node node = compare();
if (supportBean(node)) {
if (run(node)) {
afterCompletion(businessObject);
return true;
}
return false;
}
return false;
}
public String getFlowDefinitionPath() {
return flowDefinitionPath;
}
public void setFlowDefinitionPath(String flowDefinitionPath) {
this.flowDefinitionPath = flowDefinitionPath;
}
}
/**
* 默认流程执行器执行器 执行顺序
* compare() -> supportBean(node) -> run(node) -> afterCompletion(businessObject)
* @author shadow
*
*/
public class DefaultFlowActuator extends AbstractFlowActuator<Object>{
@Override
public boolean run(Node node) {
return node.run(businessObject,currentUser);
}
@Override
public void setBusinessObject(Object object,UserModel currentUser) {
this.businessObject = object;
this.currentUser = currentUser;
}
}
后续再继续改进