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,但是这个适配器能够把 ...
随机推荐
- adb 获取Android手机信息命令(2)
#Android命令 #获取手机名称 GET_PHONE_NAME = 'adb shell getprop ro.product.model' #获取手机版本 GET_PHONE_VERSION = ...
- 分布式文件系统FastDFS如何做到高可用
FastDFS是用C语言编写的一款开源的轻量级分布式文件系统.它对文件进行管理,功能包括:文件存储.文件同步.文件访问(文件上传.文件下载)等,解决了大容量存储和负载均衡的问题.特别适合以文件为载体的 ...
- 在地铁上看了zabbix 的书发现 "报警执行远程命令"
在地铁上看了zabbix 的书发现 "报警执行远程命令" 远程命令整个过程: items -> triggers -> action -> remote com ...
- 运维架构服务监控Open-Falcon
一. 介绍 监控系统是整个运维环节,乃至整个产品生命周期中最重要的一环,事前及时预警发现故障,事后提供翔实的数据用于追查定位问题.监控系统作为一个成熟的运维产品,业界有很多开源的实现可供选择.当公司刚 ...
- C#学习笔记-策略模式
题目:做一个商场收银的小程序,可能会出现的情况包括:正常收费,九折优惠,七折优惠,满300减50等各种不同随时会变化的优惠活动. 界面如下: 分析: 首先我们对于收钱写一个父类CashSuper.这个 ...
- [转]python json.dumps 中的ensure_ascii 参数引起的中文编码
本文转自: 梁小白博客(http://biangbiang.cnblogs.com) 在使用json.dumps时要注意一个问题 >>> import json >>&g ...
- Zabbix实战-简易教程--排错(持续收集中)
一.安装错误 1.zabbix 安装故障之无法跳到下一步或点击下一步没反应 执行命令:chownnginx:nginx /var/lib/php/session/ -R 2.proxy上无法采集交 ...
- 我们编写 React 组件的最佳实践
刚接触 React 的时候,在一个又一个的教程上面看到很多种编写组件的方法,尽管那时候 React 框架已经相当成熟,但是并没有一个固定的规则去规范我们去写代码. 在过去的一年里,我们在不断的完善我们 ...
- AtCoder Regular Contest 071
C - 怪文書 / Dubious Document 题意:定义一种无序的子序列:在原串中随意地取字符并随意打乱顺序.求多个字符串的最长公共无序子序列. #include<cstdio> ...
- 51 Nod 1005 大数加法【Java大数乱搞,python大数乱搞】
1005 大数加法 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 给出2个大整数A,B,计算A+B的结果. Input 第1行:大数A 第2行:大数B (A,B的长度 ...