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;@Testpublic void testSleep() {Command wakeupCommand = new Command() {@Overridepublic 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;}/*** 执行.*/@Overridepublic 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() {@Overridepublic 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;}/*** 执行.*/@Overridepublic void execute() {System.out.print(itsChar);if (!stop) {delayAndRepeat();}}private void delayAndRepeat() {engine.addCommand(new SleepCommand(this, engine, itsDelay));}
}