组合模式(Composite)
对于单个对象或者具有相同行为的由单个对象组合而成的对象套件,在客户端调用时,为了不加以区分是单个对象还是对象套件,即使用统一的对象行为入口,这种场景下可以使用此模式。该模式涉及到三个概念:
Component 指的是单个对象或者对象套件的统一行为接口声明
Leaf 指的是单个对象
Composite 指的是由单个对象组成的对象套件
在分析适配器模式的时候,我们说过在测试用例被转换为testcase之后,所有testcase会被组装成一个testsuite(这个是testcase对象的集合),Junit在执行这个测试请求的时候,会分析,是一个testcase还是testsuite,如果是一个testcase好办,如果是testsuite就要分解,然后逐个执行,这样很麻烦,代码会臃肿,这种场景下,可以使用组合模式,它可以屏蔽掉客户端在调用时,如何区分testcase还是testsuite的问题;
上图说明了在Junit测试框架中,各个类对应组合模式中的概念,在Junit执行前期阶段,会构建TestSuite对象,下面从代码分析Junit框架是如何不再区分单个对象还是对象套件的:
public TestSuite(final Class theClass) { fName= theClass.getName(); try { getTestConstructor(theClass); // Avoid generating multiple error messages } catch (NoSuchMethodException e) { addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); return; }if (!Modifier.isPublic(theClass.getModifiers())) { addTest(warning("Class "+theClass.getName()+" is not public")); return; } Class superClass= theClass; Vector names= new Vector(); while (Test.class.isAssignableFrom(superClass)) { Method[] methods= superClass.getDeclaredMethods(); for (int i= 0; i < methods.length; i++) { addTestMethod(methods[i], names, theClass); } superClass= superClass.getSuperclass(); } if (fTests.size() == 0) addTest(warning("No tests found in "+theClass.getName()));
}
这是通过构造方法来构建一个TestSuite对象,其中的代码在上篇适配器模式分析的文章中已经讲解过,这里不再赘述,所有测试用例被转换为testcase后,放在VECTOR中,最后TestSuite对象构建完毕,另外,TestSuite还提供了一个addTestSuite方法,用来递归构建TestSuite对象,最终可以形成一颗树,代码如下:
/** * Adds the tests from the given class to the suite */ public void addTestSuite(Class testClass) { addTest(new TestSuite(testClass)); }
此时对于Junit测试框架来说,他所执行的统一入口还是Test接口定义的 run方法,而TestSuit也遵循这一接口的规定,我们看看它的run方法代码:
/** * Runs the tests and collects their result in a TestResult. */ public void run(TestResult result) { for (Enumeration e= tests(); e.hasMoreElements(); ) { if (result.shouldStop() ) break; Test test= (Test)e.nextElement(); runTest(test, result); } }public void runTest(Test test, TestResult result) { test.run(result); }</pre>
通过这段代码,我们可以知道在TestSuite内部执行run方法的时候,已经对其内部包含的TestCase进行逐个解析,执行run方法,那么对于Junit测试框架来说,这是透明的,测试框架调用的仍然是基于Test接口的实现,TestSuite内部如何封装,不重要,重要的是调用其统一入口run方法,只要保证这个统一入口不变,客户端调用就不必修改任何代码,即使TestSuite再怎么递归组装。引声一下,TestSuite的自由组装,给我们提供了一个非常强大的功能,就是我们可以增加新的TestCase类型,对TestCase进行功能上的增强和扩展。下一节,我们深入点,分析模板模式,精彩继续!
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于