Command 和 Active Object 模式
Command 模式是封装了一个没有任何变量的函数。
public interface Command {
public void do();
}
简单的Command
打印机工作流
开启/关闭继电器—RelayOnCommand、RelayOffCommand;
开启/关闭发动机—MotorOnCommand、MotorOffCommand;
开启/关闭离合器—ClutchOnCommand、ClutchOffCommand;
事务操作
另一个Command 模式的常见用法是创建和执行事务操作(Transactions)。当用户决定增加一个新雇员时,该用户必须详细指明成功创建一条雇员记录所需的所有信息。在使用这些信息前,系统需要验证这些信息语法和语义上的正确性。Command 对象存储了还未验证的数据,实现了实施验证的方法,并且实现了最后执行事务操作的方法。
validate() 方法检查所有数据并确保数据是有意义的。
execute() 方法用已经验证过的数据去更新数据库。
Active Object 模式
Active Object 模式是使用Command 模式的地方之一。这是实现多线程控制的一项古老的技术。
ActiveObjectEngine.java
import java.util.LinkedList;
public class ActiveObjectEngine {
/**
* 命令链表.
*/
private LinkedList<Command> itsCommands = new LinkedList<>();
/**
* 添加命令.
* @param c 命令.
*/
public void addCommand(Command c) {
this.itsCommands.add(c);
}
/**
* 运行.
*/
public void run() {
while (!itsCommands.isEmpty()) {
Command c = itsCommands.getFirst();
itsCommands.removeFirst();
System.out.println("--->Command.execute()");
c.execute();
}
}
}
Command.java
public interface Command {
public void execute();
}
SleepCommandTest.java
import org.junit.Assert;
import org.junit.Test;
public class SleepCommandTest {
private boolean commandExecuted = false;
@Test
public void testSleep() {
Command wakeupCommand = new Command() {
@Override
public void execute() {
commandExecuted = true;
System.out.println("WakeUp...");
}
};
ActiveObjectEngine engine = new ActiveObjectEngine();
SleepCommand sleepCommand = new SleepCommand(wakeupCommand, engine, 1000);
engine.addCommand(sleepCommand);
long start = System.currentTimeMillis();
engine.run();
long stop = System.currentTimeMillis();
long sleepTime = (stop - start);
Assert.assertTrue("SleepTime " + sleepTime + " expected > 900", sleepTime > 900);
Assert.assertTrue("SleepTime " + sleepTime + " expected < 1100", sleepTime < 1100);
Assert.assertTrue("Command Executed", commandExecuted);
}
}
SleepCommand.java
public class SleepCommand implements Command {
/**
* 唤醒命令.
*/
private Command wakeupCommand = null;
/**
* 引擎.
*/
private ActiveObjectEngine engine = null;
/**
* 休眠时间.
*/
private long sleepTime = 0l;
/**
* 开始时间.
*/
private long startTime = 0l;
/**
* 是否已开始.
*/
private boolean started = false;
/**
* 构造器.
*/
public SleepCommand(final Command wakeupCommand, final ActiveObjectEngine engine, final long milliseconds) {
super();
this.wakeupCommand = wakeupCommand;
this.engine = engine;
this.sleepTime = milliseconds;
}
/**
* 执行.
*/
@Override
public void execute() {
long currentTime = System.currentTimeMillis();
if (!started) {
started = true;
startTime = currentTime;
engine.addCommand(this);
} else if ((currentTime - startTime) < sleepTime) {
engine.addCommand(this);
} else {
engine.addCommand(wakeupCommand);
}
}
}
和等待一个事件的多线程程序类比。当多线程程序中的一个线程等待一个事件时,它通常使用一些操作系统调用来阻塞自己直到事件发生。这里并没有阻塞,如果所等待的((currentTime - startTime) < sleepTime) 这个事件没有发生,它只是把自己放回到ActiveObjectEngine 中。
采用该技术的变体去构建多线程系统已经是一个很常见的实践。这种类型的线程被称为run-to-completion 任务(RTC),因为每个Command 实例在下一个Command 实例可以运行之前就运行完成了。RTC 意味着Command 实例不会阻塞。
DelayedCommand.java
public class DelayedCommand implements Command {
/**
* 延迟毫秒数.
*/
private long itsDelay;
/**
* 字符.
*/
private char itsChar;
/**
* 引擎.
*/
private static ActiveObjectEngine engine = new ActiveObjectEngine();
/**
* 是否停用.
*/
private static boolean stop = false;
public static void main(String[] args) {
engine.addCommand(new DelayedCommand(100, '1'));
engine.addCommand(new DelayedCommand(300, '3'));
engine.addCommand(new DelayedCommand(500, '5'));
engine.addCommand(new DelayedCommand(700, '7'));
Command stopCommand = new Command() {
@Override
public void execute() {
DelayedCommand.stop = true;
}
};
engine.addCommand(new SleepCommand(stopCommand, engine, 2000));
engine.run();
}
/**
* 构造器.
*/
public DelayedCommand(long delay, char c) {
super();
itsDelay = delay;
itsChar = c;
}
/**
* 执行.
*/
@Override
public void execute() {
System.out.print(itsChar);
if (!stop) {
delayAndRepeat();
}
}
private void delayAndRepeat() {
engine.addCommand(new SleepCommand(this, engine, itsDelay));
}
}