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,但是这个适配器能够把 ...
随机推荐
- windows 驱动开发入门——驱动中的数据结构
最近在学习驱动编程方面的内容,在这将自己的一些心得分享出来,供大家参考,与大家共同进步,本人学习驱动主要是通过两本书--<独钓寒江 windows安全编程> 和 <windows驱动 ...
- [转载自阿里丁奇]各版本MySQL并行复制的实现及优缺点
MySQL并行复制已经是老生常谈,笔者从2010年开始就着手处理线上这个问题,刚开始两三年也乐此不疲分享,现在再提这个话题本来是难免"炒冷饭"嫌疑. 最近触发再谈这个话题,是 ...
- App开发 对生命周期的处理
//获取到当前所在的视图 - (UIViewController *)presentingVC:(UIApplication *)application{ UIWindow * window = ap ...
- Lottie的使用
一.简介 Lottie是Airbnb开源的一个面向IOS.Android.React Native的动画库,能分析Adobe After Effects导出的动画,并且能让原生App像使用静态素材一样 ...
- 我的第一个spring_boot项目
springBoot火了有一段时间了,现在才接触,着实没跟上节奏.. 一.创建项目并跑起来 目的很简单,只要配置好springBoot环境,并成功启动,且能访问到我项目下的任一资源即可 1 下载mav ...
- python网络数据采集(伴奏曲)
这里是前章,我们做一下预备.之前太多事情没能写博客~.. (此博客只适合python3x,python2x请自行更改代码) 首先你要有bs4模块 windows下安装:pip3 ...
- 谈谈Grunt,NPM,Gulp
随着前端工程化的趋势,产生了越来越多的构建工具,而其中比较优秀的就是grunt,npm,gulp,今天我来说说这三者间的区别以及他们的优缺点. 相信一般前端开发者选择构建工具的时候,更多的是看个人习惯 ...
- 2017年浙江理工大学程序设计竞赛校赛 题解&源码(A.水, D. 简单贪心 ,E.数论,I 暴力)
Problem A: 回文 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 1719 Solved: 528 Description 小王想知道一个字 ...
- Codeforces 834D The Bakery【dp+线段树维护+lazy】
D. The Bakery time limit per test:2.5 seconds memory limit per test:256 megabytes input:standard inp ...
- 2017ecjtu-summer training #4 CodeForces 731C
C. Socks time limit per test 2 seconds memory limit per test 256 megabytes input standard input outp ...