我的步骤执行容器StepFramework
<main>add,multiply,divideAndSubtractionStepSuite</main><all-step><step name="add" params-ref="add"/><step name="multiply" params-ref="multiply"/><step name="divideAndSubtractionStepSuite" params-ref="divideAndSubtractionStepSuite"/></all-step>
看了这个文件,即使我不说明,都大概能猜到该程序要依次运行add,multiply,divideAndSubtractionStepSuite这三个步骤,步骤对应的类和参数在<step/>中得到进一步的描述。
?
细节1
divideAndSubtractionStepSuite
?这个步骤其实集合了除法步骤和减法步骤,融合为一步骤(具体参见附件或实例代码)。这个特性是为了满足可读性的要求。例如一个增量编译,包含了下载增量文件,编译,COPY文件三个子步骤,融合为一个名为compileDiff的步骤,显然好读,更易理解。
?
细节2?
配置文件没有考虑StepSuite的配置项,只有step配置项。
?
stepframwork将包含多个step和stepSuite组件的集合称为stepSuite。目前对StepSuite下的各个组件共用一个参数集合,因为考虑到一个StepSuite,大多数情况下是不应该存在重复参数的,而且,我认为一个StepSuite作为一个namespace已经足够了,细化到Step似乎有些多余。万一如果一个StepSuite下真存在重复组件和重复参数名,实际上很可能应该将一个StepSuite分拆为两个。另一方面,考虑到如果要使每个StepSuite组件下的所有Step单独使用自己的参数集合,配置将变得复杂,后面的人维护起来也麻烦。stepframwork并不是不能实现每个Step对应一个参数集合,而是为了维护和易学,stepframework做了一个“不完美”的选择, 因此配置文件中没有类似
<stepSuite name="divideAndSub">
?<step step-ref="divide"/>
?<step step-ref="sub"/>
</stepSuite>
的配置。但是可以通过写一个TestSuite的子类实现同等效果,也很简单。
例如:
?
package test;import stepframework.StepSuite;public class TryStepSuit extends StepSuite{public TryStepSuit(){this.addStep(new Divide()).addStep(new Sub());}}
?
?
?
2 每个步骤组件关联一个参数集合,当参数集合中查找不到想要的参数,则使用责任链在前面步骤组件关联的参数集合中查找参数。
?
这样设计是因为通常情况下,后面执行的步骤需要前面步骤的某些参数,而责任链能非常优雅的实现这一点。责任链还提供其他两个好处:
?a)免去了重用前面的某个步骤组件时需要在参数名前面添加前缀的问题,因为即使重名,责任链保证首先会读到该组件实例关联的参数。
?b)利用责任链,可以把前一步骤的执行结果,传递到下一个步骤。
?
此外,每个步骤组件关系的参数集合,都是由stepframework自动注入到具体的步骤组件对象中,无需步骤组件开发人员处理。
?
题外话:在现在使用责任链来实现参数的动态查找之前,我是这样设计的,一个步骤组件关联一个参数集合,该集合包含了该步骤所需的所有参数,但是这些参数与其他步骤的参数有不少重复。对于一个有代码洁癖的程序原来说,这是不能容忍的事情,苦思一番之后,灵感乍现,javascript原型链不就是解决我这个问题的最佳实践吗?于是,责任链的实现诞生了。
?
<all-params><params name="add"><param name="left" value="10"/><param name="right" value="20"/><param name="result" value=""/></params><params name="multiply"><param name="multi_num" value="3"/></params><params name="divideAndSubtractionStepSuite"><param name="div_num" value="2"/><param name="sub_num" value="3"/></params></all-params>
?
package stepframework;import java.util.Map;public class Params {private Map<String,String> map;private Params parent;public Params(Map<String, String> map, Params parent) {super();this.map = map;this.parent = parent;}public void put(String paramName, String paramValue){map.put(paramName, paramValue);}//责任链查找public String get(String paramName){String paramValue = map.get(paramName);if(null != paramValue){return paramValue;}else if(null != parent){return parent.get(paramName);}else{return "";}}}
?
3 对于步骤集合(StepSuite)和单一步骤(Step),使用了聚合模式,统一作为一个IStep的实现,容器通过该方式,统一处理所有的步骤,而无视所谓步骤与子步骤,程序变得更简单。
?
package stepframework;import java.util.ArrayList;import java.util.List;public class StepSuite implements IStep{private Params params;private List<IStep> steps = new ArrayList<IStep>(); public StepSuite(){}public StepSuite addStep(IStep step){steps.add(step);return this;}//聚合模式的关键,集合对象,依次执行每个子对象@Overridepublic Result run() {for(IStep step : steps){step.setParams(params);Result rs = step.run();if(!rs.isSuccess()){return rs;}}return Result.SUCCESS;}public void setParams(Params params){this.params = params;}public void putParam(String paramName, String paramValue){params.put(paramName, paramValue);}public String getParam(String paramName){return params.get(paramName);}}
?
StepFramework使用示例
stepframework使用非常简单,只需两步:1. 扩展基类创建步骤组件,2. step.xml中描述如何运行这些组件
?
下面演示了加减乘除4个步骤的依次执行,每个步骤执行的结果,都能传递到后一步骤。
?
1. 编写步骤类,继承Step,或者StepSuite(包含多个Step或者StepSuite)。
?
下面定义了加减乘除4个Step,和1个综合了“除和减”两个Step的集合StepSuite。
?
对于单一步骤Step,需要继承Step类,重写run()方法,编写步骤的具体逻辑。在run方法中使用getParam查找参数,使用putParam设置传递到后面步骤的结果参数。如果执行失败,创建一个Result对象,填充错误信息 ,并且stepframework会马上体制,如果执行成功,直接返回Result.SUCCESS即可。
?
对于Step或StepSuite的步骤集合StepSuite,需要继承StepSuite类,编写构造函数,调用add()方法添加所需的Step或StepSuite。这些Step和StepSuite都共同关联同一个参数结合params。
?
package test;import stepframework.Result;import stepframework.Step;public class Add extends Step{@Overridepublic Result run() {String left = this.getParam("left");String right = this.getParam("right");Integer i = Integer.valueOf(left) + Integer.valueOf(right);String result = String.valueOf(i);this.putParam("result",result );System.out.println(left+"+"+right+"="+result);return Result.SUCCESS;}}
?
package test;import stepframework.Result;import stepframework.Step;public class Multiply extends Step{@Overridepublic Result run() {String result = this.getParam("result");String multi_num = this.getParam("multi_num");String orginResult = result;result = String.valueOf(Integer.valueOf(result)*Integer.valueOf(multi_num));System.out.println(orginResult+"*"+multi_num+"="+result);this.putParam("result", result);return Result.SUCCESS;}}
?
package test;import stepframework.Result;import stepframework.Step;public class Divide extends Step{@Overridepublic Result run() {String result = this.getParam("result");String divNum = this.getParam("div_num");String orginResult = result;result = String.valueOf(Integer.valueOf(result)/Integer.valueOf(divNum));System.out.println(orginResult+"/"+divNum+"="+result);this.putParam("result", result);return Result.SUCCESS;}}
?
package test;import stepframework.Result;import stepframework.Step;public class Sub extends Step{@Overridepublic Result run() {String result = this.getParam("result");String sub_num = this.getParam("sub_num");String orginResult = result;result = String.valueOf(Integer.valueOf(result) - Integer.valueOf(sub_num));System.out.println(orginResult+"-"+sub_num+"="+result);this.putParam("result", result);return Result.SUCCESS;}}
?
package test;import stepframework.StepSuite;public class TryStepSuit extends StepSuite{public TryStepSuit(){this.addStep(new Divide()).addStep(new Sub());}}
?
2. 配置step.xml,让stepframework自动按顺序执行各个步骤。
? ? a)在step.xml中的<step/>中,添加上步骤名,步骤实现类和引用的参数集合名。
? ? b)在step.xml中的<params/>中,配置每个步骤所需要的参数。
? ? c)在step.xml中main中,配置要执行的步骤,stepframework会按照先后顺序执行。
? ? d)step.xml放在classpath下
<step-root><main>add,multiply,divideAndSubtractionStepSuite</main><all-step><step name="add" params-ref="add"/><step name="multiply" params-ref="multiply"/><step name="divideAndSubtractionStepSuite" params-ref="divideAndSubtractionStepSuite"/></all-step><all-params><params name="add"><param name="left" value="10"/><param name="right" value="20"/><param name="result" value=""/></params><params name="multiply"><param name="multi_num" value="3"/></params><params name="divideAndSubtractionStepSuite"><param name="div_num" value="2"/><param name="sub_num" value="3"/></params></all-params></step-root>
?3 调用StepRunner类执行程序
public class Main {public static void main(String[] args) throws URISyntaxException, DocumentException, ClassNotFoundException, InstantiationException, IllegalAccessException{StepRunner.run();}}
?