junit设计模式--适配器模式
- 适配器(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<RunnerBuilder> 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();
}
}
junit设计模式--适配器模式的更多相关文章
- 20. 星际争霸之php设计模式--适配器模式
题记==============================================================================本php设计模式专辑来源于博客(jymo ...
- Java设计模式——适配器模式
JAVA 设计模式 适配器模式 用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器 ...
- linkin大话设计模式--适配器模式
linkin大话设计模式--适配器模式 大家知道,在java中只允许单继承,但是在实际问题中往往都需要多继承,java引入了接口这一概念.(一个类可以实现多个接口) 由于接口中都是抽象方法,那么我们在 ...
- php设计模式适配器模式
php设计模式适配器模式 简介 适配器模式(有时候也称包装样式或者包装)将一个类的接口适配成用户所期待的.一个适配允许通常因为接口不兼容而不能在一起工作的类工作在一起. 其实就是通过一个转换类,这个转 ...
- 【设计模式】Java设计模式 - 适配器模式
[设计模式]Java设计模式 - 适配器模式 不断学习才是王道 继续踏上学习之路,学之分享笔记 总有一天我也能像各位大佬一样 原创作品,更多关注我CSDN: 一个有梦有戏的人 准备将博客园.CSDN一 ...
- [Head First设计模式]身边的设计模式——适配器模式
系列文章 [Head First设计模式]山西面馆中的设计模式——装饰者模式 [Head First设计模式]山西面馆中的设计模式——观察者模式 [Head First设计模式]山西面馆中的设计模式— ...
- JAVA 设计模式 适配器模式
用途 适配器模式 (Adapter) 将一个类的接口转换成客户希望的另外一个接口. Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作. 适配器模式是一种结构型模式. 结构
- Java设计模式 - 适配器模式
概念: 将一个类的接口,转换成客户期望的另一个接口.适配器模式让原来接口不兼容的类可以在一起工作. 解决的问题: 提供类似于中间人的作用:把原本不兼容.不能一起工作的接口组合在一起,使得它们能够在一起 ...
- 24种设计模式--适配器模式【Adapter Pattern】
今天讲适配器模式,这个模式也很简单,你笔记本上的那个拖在外面的黑盒子就是个适配器,一般你在中国能用,在日本也能用,虽然两个国家的的电源电压不同,中国是 220V,日本是 110V,但是这个适配器能够把 ...
随机推荐
- win10安装Tensorflow
win10安装Tensorflow 前提: 保证你的pip>=8.1版本 否则利用python -m pip install -U pip 进行升级,或下载pip源文件 确定你的显卡是否支持c ...
- Kylin与CDH兼容性剖析
1. 概述 Apache Kylin™是一个开源的分布式分析引擎,提供Hadoop之上的SQL查询接口及多维分析(OLAP)能力以支持超大规模数据,最初由eBay Inc. 开发并贡献至开源社区.它能 ...
- 【读书笔记】【深入理解ES6】#6-Symbol和Symbol属性
在ES5及早期版本中,JS语言包含5中原始类型: 字符串型 数字型 布尔型 null undefined ES6引入了第六种原始类型: Symbol 创建Symbol let firstName = ...
- 进入docker登录psql数据库对特定表进行操作
查看docker镜像 docker ps 运行镜像的脚本命令 docker exec -it 08 bash # 选择id为08开头的镜像运行bash 登录数据库 (1)直接登录 执行命令:psql ...
- JDK源码 - ArrayList
/** * ArrayList源码分析 * @author liyong * */ public class Util { @SuppressWarnings("unchecked" ...
- Vivado常见问题集锦
5. Vivado软件更新新版后更新IP 当更新到新版本的Vivado后,之前的一些工程的IP是不能直接打开使用的,这个时候我们只需要使用新版本的Vivado更新一下每个工程的IP即可,使用新版本Vi ...
- ogg的孩子-无损音频编解码flac
flac是一款无损的音频压缩编码,它的特点是对音频文件进行无损压缩,目前是被很多软件及智能硬件产品所支持. 从技术上来讲,该编解码的优点还是十分明显的,无损压缩,策略灵活,解码快速,硬件支持等特点都是 ...
- XML Schema格式的"日期型数据”数据库存取
对于XML Schema格式的"日期型数据"在数据库中存于datetime字段的时候,出现错误 mysql> select @@sql_mode; +------------ ...
- 51 nod 1211 数独 DLX
原题链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1211 调了挺久的,自己的一份舞蹈链模板…… 算是在网上见到的模 ...
- [51nod1671]货物运输
公元2222年,l国发生了一场战争. 小Y负责领导工人运输物资. 其中有m种物资的运输方案,每种运输方案形如li,ri.表示存在一种货物从li运到ri. 这里有n个城市,第i个城市与第i+1个城市相连 ...