博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
junit设计模式--适配器模式
阅读量:6716 次
发布时间:2019-06-25

本文共 7917 字,大约阅读时间需要 26 分钟。

  • 适配器(Adapter)模式
  在软件系统中,由于环境的变化,常常需要将“一些现存的对象”放在新的环境中应用,但是新环境要求的接口是这些现存对象所不满足的。那么如何应对这种“迁移的变化”?如何既能利用现有对象的良好实现,同时又能满足新的应用环境所要求的接口?  这就要利用Adapter模式。
  • Adapter模式意图
  1,将一个类的接口转换成客户希望的另一个接口。
  2,Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 适配器(Adapter)模式的构成
  1,目标抽象角色(Target)

  定义客户要用的特定领域的接口。

  2,适配器(Adapter)

调用另一个接口,作为一个转换器。

  3,适配类(Adaptee)

  定义一个接口,Adapter需要接入。即系统中原有的类,需要适配使之可以利用。

  4,客户端(Client)

协同对象符合Adapter适配器。

  • 适配器的分类
  适配器模式(Adapter Pattern)主要分为三种:

  1.基于类的继承方式,也称类适配器。

  2.基于对象组合方式,也称对象适配器,推荐这种实现而不是上一种使用继承。

  3.缺省的适配器模式(AWT, Swing事件模型所采用的适配器模式)。

OK,现在我们分别来写几个例子:

1,基于类的继承方式。

package org.linkinpark.junit.testjunit;/** * @创建作者: LinkinPark * @创建时间: 2016年2月5日 * @功能描述: 新需求的需要的接口 */public interface Target{		// 新需求需要实现的接口	void method();}
package org.linkinpark.junit.testjunit;public class TargetImpl implements Target{	@Override	public void method()	{		System.out.println("这里是新需求的方法。。。");	}}
package org.linkinpark.junit.testjunit;/** * @创建作者: LinkinPark * @创建时间: 2016年2月5日 * @功能描述: 需要被适配的对象 */public class Adaptee{		public void method()	{		System.out.println("这里是原来的方法。。。");	}}
package org.linkinpark.junit.testjunit;/** * @创建作者: LinkinPark * @创建时间: 2016年2月5日 * @功能描述: 适配器 */public class Adapter extends Adaptee implements Target{	@Override	public void method()	{		super.method();	}}
package org.linkinpark.junit.testjunit;import org.junit.Test;public class AdapterTest{		@Test	public void testAdapter()	{		Target target = new Adapter();		target.method();				Target target1 = new TargetImpl();		target1.method();	}}
OK,现在我们来看下控制台的输出,OK,完美的兼容了新旧版本。

这里是原来的方法。。。这里是新需求的方法。。。

2,基于组合的方式

其他类不用动,只是将原来的适配器由继承旧对象变成组合旧对象就OK了。代码如下:

package org.linkinpark.junit.testjunit;/** * @创建作者: LinkinPark * @创建时间: 2016年2月5日 * @功能描述: 适配器 */public class Adapter implements Target{	private Adaptee adaptee;		// 这里可以构造器注入旧对象,也可以在上面的属性set()设值	public Adapter(Adaptee adaptee)	{		super();		this.adaptee = adaptee;	}	@Override	public void method()	{		adaptee.method();	}}
package org.linkinpark.junit.testjunit;import org.junit.Test;public class AdapterTest{	@Test	public void testAdapter()	{		Target target = new Adapter(new Adaptee());		target.method();		Target target1 = new TargetImpl();		target1.method();	}}
运行上面的测试代码,控制台同样的输出,OK,没问题。

3,关于第三种方式,这里不做赘述了。就是在有多个方法的接口和一个不想实现那么多方法的实现类中加入实现所有接口方法的一层,加入的这一层的实现可以是空实现,这个无所谓。在自己真正需要的实现类中去重写加入的那一层里面自己敢兴趣的方法就OK了。

来总结一下:

  • 适配器(Adapter)模式的适用性
  1,对象需要利用现存的并且接口不兼容的类。
  2,需要创建可重用的类以协调其他接口可能不兼容的类。
  • JUnit中的适配器模式:
  1,JUnit3.8的TestCase的源代码中,真正运行测试源码的代码如下,
public void runBare() throws Throwable {        setUp();        try {            runTest();        }        finally {            tearDown();        }    }
runTest()中执行我们的测试方法。测试方法testXXX要求必须是public void并且不带参数的,这里就使用了适配器模式。runTest()的实现如下:

protected void runTest() throws Throwable	{		assertNotNull("测试的方法名不能为空", fName);		Method runMethod = null;		try		{			runMethod = getClass().getMethod(fName, (Class[]) null);		}		catch (NoSuchMethodException e)		{			fail("Method \"" + fName + "\" not found");		}		if (!Modifier.isPublic(runMethod.getModifiers()))		{			fail("Method \"" + fName + "\" should be public");		}		try		{			System.out.println(String.format("框架开始执行测试,执行的方法是-->%s", runMethod));			runMethod.invoke(this);			System.out.println(String.format("框架结束执行测试,执行的方法是-->%s", runMethod));		}		catch (InvocationTargetException e)		{			e.fillInStackTrace();			throw e.getTargetException();		}		catch (IllegalAccessException e)		{			e.fillInStackTrace();			throw e;		}	}
2,在junit4X系列中,junit也给我们向后兼容了38系列,这里用到的也是适配器模式。OK,我们来看一些核心代码:

Junit4X系列测试入口是junitCore类:

public class JUnitCore{	private final RunNotifier notifier = new RunNotifier();	/**	 * @创建时间: 2016年1月22日	 * @相关参数: @param args	 * @功能描述: 框架测试入口	 */	public static void main(String... args)	{		String[] linkinArgs = new String[] { "org.linkinpark.commons.textui.LinkinTest4Annotation" };		Result result = new JUnitCore().runMain(new RealSystem(), linkinArgs);		System.exit(result.wasSuccessful() ? 0 : 1);	}}

/**	 * @创建时间: 2016年1月22日	 * @相关参数: @param system	 * @相关参数: @param args	 * @相关参数: @return 测试结果	 * @功能描述: 框架核心代码开始执行入口	 */	Result runMain(JUnitSystem system, String... args)	{		system.out().println("linkin-frame-junit测试框架版本号==> " + Version.id());		System.out.println("第一步:框架开始执行====");		JUnitCommandLineParseResult jUnitCommandLineParseResult = JUnitCommandLineParseResult.parse(args);		System.out.println("第二步:开始添加事件====");		RunListener listener = new TextListener(system);		addListener(listener);		System.out.println("第三步:开始运行测试====");		return run(jUnitCommandLineParseResult.createRequest(defaultComputer()));	}
关键是最后一行代码,jUnitCommandLineParseResult.createRequest()创建一个Request对象返回给测试执行器执行。OK,我们接着看下Request对象的这个方法:

public static Request classes(Computer computer, Class
... classes) { try { // 默认的可以执行所有的测试执行器builder AllDefaultPossibilitiesBuilder builder = new AllDefaultPossibilitiesBuilder(true); Runner suite = computer.getSuite(builder, classes); return runner(suite); } catch (InitializationError e) { return runner(new ErrorReportingRunner(e, classes)); } }

AllDefaultPossibilitiesBuilder是所有可能执行的测试执行器的builder,在Request中junit4X用默认的策略类computer来初始化测试执行器。

public Runner getSuite(final RunnerBuilder builder, Class
[] classes) throws InitializationError { return new Suite(new RunnerBuilder() { @Override public Runner runnerForClass(Class
testClass) throws Throwable { return getRunner(builder, testClass); } }, classes); } protected Runner getRunner(RunnerBuilder builder, Class
testClass) throws Throwable { return builder.runnerForClass(testClass); }
核心代码来了:

@Override	public Runner runnerForClass(Class
testClass) throws Throwable { List
builders = Arrays.asList(ignoredBuilder(), annotatedBuilder(), suiteMethodBuilder(), junit3Builder(), junit4Builder()); for (RunnerBuilder each : builders) { Runner runner = each.safeRunnerForClass(testClass); if (runner != null) { return runner; } } return null; } protected JUnit4Builder junit4Builder() { return new JUnit4Builder(); } protected JUnit3Builder junit3Builder() { return new JUnit3Builder(); } protected AnnotatedBuilder annotatedBuilder() { return new AnnotatedBuilder(this); } protected IgnoredBuilder ignoredBuilder() { return new IgnoredBuilder(); } protected RunnerBuilder suiteMethodBuilder() { if (canUseSuiteMethod) { return new SuiteMethodBuilder(); } return new NullBuilder(); }
循环迭代所有的可能的测试执行器,如果是38系列的测试源码,也就是说我们自己写的测试类继承于TestCase,那么就会给我们返回一个38系列的测试执行器-->Junit3Builder。

package org.linkinpark.junit.internal.builders;import org.linkinpark.commons.framework.TestCase;import org.linkinpark.junit.runner.Runner;import org.linkinpark.junit.runners.JUnit38ClassRunner;import org.linkinpark.junit.runners.model.RunnerBuilder;public class JUnit3Builder extends RunnerBuilder{	@Override	public Runner runnerForClass(Class
testClass) throws Throwable { if (isPre4Test(testClass)) { return new JUnit38ClassRunner(testClass); } return null; } boolean isPre4Test(Class
testClass) { return TestCase.class.isAssignableFrom(testClass); }}
OK,接下来就可以嫁入junit38框架来运行测试了呢。

public class JUnit38ClassRunner extends Runner implements Filterable, Sortable{	private volatile Test test;		@Override	public void run(RunNotifier notifier)	{		TestResult result = new TestResult();		result.addListener(createAdaptingListener(notifier));		getTest().run(result);	}}
OK,关于junit4我后面会专门整理到,这里简单说下这个Runner,该类是junit4X系列中所有运行执行器父类,该类里面封装一个run()的抽象方法来运行测试用例。

其实原理和38系列的差不多,但是关于注解的处理那一刻值得我们去学习下的。

这里以runner抽象类来结束这篇博客:

package org.linkinpark.junit.runner;import org.linkinpark.junit.runner.notification.RunNotifier;/** * @创建作者: LinkinPark * @创建时间: 2016年1月23日 * @功能描述: 所有测试执行器的父类 */public abstract class Runner implements Describable{	public abstract Description getDescription();	public abstract void run(RunNotifier notifier);	public int testCount()	{		return getDescription().testCount();	}}

转载于:https://www.cnblogs.com/LinkinPark/p/5232879.html

你可能感兴趣的文章
Javascript中进行遍历操作的所有方法
查看>>
JS的原型链和继承
查看>>
python中pyquery无法获取标签名的dom节点
查看>>
面试官:请手写一个webpack4.0配置
查看>>
有关getter 和 setter的使用
查看>>
JavaScript面向对象中的Function类型个人分享
查看>>
记录一次Webpack插件优化的经历
查看>>
【跃迁之路】【505天】程序员高效学习方法论探索系列(实验阶段262-2018.06.25)...
查看>>
ubuntu16.04 搭建java 环境
查看>>
关于 try 和 finally 中的 return
查看>>
JS 1-数据类型
查看>>
(Google I/O '17) Speeding Up Your Android Gradle Builds 在本地的实践
查看>>
最大似然法与似然函数
查看>>
SAPGUI里实现自定义的语法检查
查看>>
快速创建 HTML5 Canvas 电信网络拓扑图
查看>>
JS动画之定时器详解
查看>>
利用Tomcat发布基于Maven所构建的Jersey RESTful Web Service
查看>>
PHP之string之wordwrap()函数使用
查看>>
ABAP OPEN SQL里OPEN CURSOR和SELECT的比较
查看>>
【348天】我爱刷题系列107(2018.01.19)
查看>>