junit设计模式--命令者模式

时间:2021-09-08 16:34:24
  • 命令模式的意图

  将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化;

  对请求排队或记录请求日志,以及支持可撤销的操作;

  命令模式告诉我们可以为一个操作生成一个对象并给出它的一个执行方法。





  • 命令模式的构成

  1.客户角色:

  创建一个具体命令对象,并确定其接受者。



  2.命令角色:

  声明一个给所有具体命令类的抽象接口。这是一个抽象角色,通常由一个接口或抽象类实现。



  3.具体命令角色:

  定义一个接收者和行为之间的弱耦合,实现execute方法,负责调用接收者的相应操作。



  4.请求者角色:

  负责调用命令对象执行请求。



  5.接收者角色:

  负责具体实施和执行一个请求。





关于命令者模式,我前面还有一篇博客。说的简单点命令者模式就是将请求对象和请求对象的实现解耦,2个都作为参数实现动态传参。在Java1.8中已经有了函数式接口,也就是专门针对Java不能将一段代码块作为参数传入一个方法做的补充。

OK,现在我们来写个例子吧。

package org.linkinpark.junit.testjunit;

/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月5日
* @功能描述: 命令者模式接口
*/
public interface Command
{ void execute(); }

package org.linkinpark.junit.testjunit;

/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月5日
* @功能描述: 接受者,也就是处理请求的那个对象
*/
public class Receiver
{ public void doSomething()
{
System.out.println("doSomething in receiver。。。");
} }
package org.linkinpark.junit.testjunit;

/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月5日
* @功能描述: 接受者和行为之间的弱耦合实现
*/
public class ConcreteCommand implements Command
{ private Receiver receiver; public ConcreteCommand(Receiver receiver)
{
super();
this.receiver = receiver;
} @Override
public void execute()
{
receiver.doSomething();
} }
package org.linkinpark.junit.testjunit;

/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月5日
* @功能描述: 请求执行器,创建一个请求接受者,然后触发命令者接口中对接受者行为的触发
*/
public class Invoker
{ private Command command; public Invoker(Command command)
{
super();
this.command = command;
} public void doAction()
{
command.execute();
} }
package org.linkinpark.junit.testjunit;

import org.junit.Test;

public class CommandTest
{ @Test
public void testCommand()
{
// 接收者
Receiver receiver = new Receiver(); // 命令:具体命令关联接收者
Command command = new ConcreteCommand(receiver); // 调用者
Invoker invoker = new Invoker(command); // 调用者调用命令,实际是所关联的接收者执行操作
invoker.doAction();
} }



OK,最后我们写了一个测试了,我们看下控制台,成功执行了我们想要的逻辑。

doSomething in receiver。。。

上面的这几段代码,轻松的实现了一个对象和该对象行为之间的松耦合。

1,假如我们现在想要改变该对象的行为,其他的代码根本不需要动。只需要修改command接口中对象的行为代码就OK。比如我们现在想在对象执行doSomething()方法前后执行特定的逻辑,直接这里修改就OK。比如我们现在对concreteCommand做如下修改:

package org.linkinpark.junit.testjunit;

/**
* @创建作者: LinkinPark
* @创建时间: 2016年2月5日
* @功能描述: 接受者和行为之间的弱耦合实现
*/
public class ConcreteCommand implements Command
{ private Receiver receiver; public ConcreteCommand(Receiver receiver)
{
super();
this.receiver = receiver;
} @Override
public void execute()
{
System.out.println("这里是对象执行doSomething()之前的行为。。。");
receiver.doSomething();
System.out.println("这里是对象执行doSomething()之后的行为。。。");
} }

控制台输出如下:

这里是对象执行doSomething()之前的行为。。。
doSomething in receiver。。。
这里是对象执行doSomething()之后的行为。。。

2,假如我们现在不想改变该对象的行为,而是想改变测试对象。那么我们只需要直接修改receiver对象就可以,比如我们继承或者重新组合一个对象。我们现在对Receiver对象派生一个子类:

package org.linkinpark.junit.testjunit;

public class SonReceiver extends Receiver
{ @Override
public void doSomething()
{
super.doSomething();
System.out.println("上面是父类的执行,这里开始走自己的逻辑。。。");
} }

控制台输出如下:

这里是对象执行doSomething()之前的行为。。。
doSomething in receiver。。。
上面是父类的执行,这里开始走自己的逻辑。。。
这里是对象执行doSomething()之后的行为。。。

在JUnit中的体现

  我们编写的TestCase就像是一个命令,通过调用器调用后,JUnit框架中有相应的接收者来执行我们的测试方法。TestCase是真正的测试执行者,每个测试用例都会生成一个TestCase对象,这就是典型的命令者模式。TestCase实现Test接口中定义的方法,测试开发人员只需要关注这些接口方法,而不必关心TestCase以及junit内部的实现细节,run()方法就是Command模式中Execute()方法。

public void run(TestResult result)
{
result.run(this);
}

使用命令(Command)模式后给系统的架构带来了哪些效果

  Command模式将实现请求的一方(TestCase)和调用一方(JUnit)进行解耦。

  Command模式使得新的TestCase很容易加入,无需改变已有的类,只需继承TestCase类即可,这样方便了测试人员。

  Command模式可以将多个TestCase进行组合成一个复合命令,TestSuite就是复合命令,它使用了Composite模式。

  Command模式容易把请求的TestCase组合成请求队列,这样使接收请求的一方(JUnit Framework)容易决定是否执行请求,一旦发现测试用例失败或者错误可以立刻停止,进行报告。