概述
Command(CoR)模式也叫命令模式,是由GoF提出的23种软件设计模式的一种。本文介绍设计模式中的(Command)模式的概念,用法,并用Command模式给出了一个简单的execute/undo实现。
Command模式是行为模式之一,Command模式通过被称为Command的类封装了对目标对象的调用行为以及调用参数。
在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。
但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。
- 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。
- 调用前后需要对调用参数进行某些处理。
- 调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。
一般来说,Command模式通常可应用到以下场景:
Multi-level undo(多级undo操作)
如果系统需要实现多级回退操作,这时如果所有用户的操作都以command对象的形式实现,系统可以简单地用stack来保存最近执行的命令,如果用户需要执行undo操作,系统只需简单地popup一个最近的command对象然后执行它的undo()方法既可。
Transactional behavior(原子事务行为)
借助command模式,可以简单地实现一个具有原子事务的行为。当一个事务失败时,往往需要回退到执行前的状态,可以借助command对象保存这种状态,简单地处理回退操作。
Progress bars(状态条)
假如系统需要按顺序执行一系列的命令操作,如果每个command对象都提供一个getEstimatedDuration()方法,那么系统可以简单地评估执行状态并显示出合适的状态条。
Wizards(导航)
通常一个使用多个wizard页面来共同完成一个简单动作。一个自然的方法是使用一个command对象来封装wizard过程,该command对象在第一个wizard页面显示时被创建,每个wizard页面接收用户输入并设置到该command对象中,当最后一个wizard页面用户按下“Finish”按钮时,可以简单地触发一个事件调用execute()方法执行整个动作。通过这种方法,command类不包含任何跟用户界面有关的代码,可以分离用户界面与具体的处理逻辑。
GUI buttons and menu items(GUI按钮与菜单条等等)
Swing系统里,用户可以通过工具条按钮,菜单按钮执行命令,可以用command对象来封装命令的执行。
Thread pools(线程池)
通常一个典型的线程池实现类可能有一个名为addTask()的public方法,用来添加一项工作任务到任务队列中。该任务队列中的所有任务可以用command对象来封装,通常这些command对象会实现一个通用的接口比如java.lang.Runnable。
Macro recording(宏纪录)
可以用command对象来封装用户的一个操作,这样系统可以简单地通过队列保存一系列的command对象的状态就可以记录用户的连续操作。这样通过执行队列中的command对象,就可以完成“Play back”操作了。
Networking
通过网络发送command命令到其他机器上运行。
Parallel Processing(并发处理)
当一个调用共享某个资源并被多个线程并发处理时。
等等
Command
Command抽象类。
ConcreteCommand
Command的具体实现类。
Receiver
需要被调用的目标对象。
Invorker
通过Invorker执行Command对象。
Client
调用方。
下面,我们使用Command模式实现一个简单的execute/undo操作。
在该范例中,我们有一个简单的操作:对字符串做append操作,这个操作由Receiver类实现;另外,我们需要记录操作历史,并能简单加以回退(undo),所以我们采用Command模式实现。
文件一览:
Client
测试类
Command
Command抽象类
UndoableCommand
支持undo操作的Command抽象类,该类是Command类的子类
ConcreteCommand
具体的UndoableCommand实现类,该类继承UndoableCommand类,所以支持undo操作
CommandManager
Command管理类。该类使用Stack来管理执行过的Command对象,并提供executeCommand()与undoCommand()方法
Receiver
执行任务的目标类
Invoker
这个类在我们的例里没有被用到,但我们仍给出了它的一个参考实现,不过用注释表示它不可用
- import java.util.Stack;
- public class Client {
- /**
- * Test Command Pattern
- *
- */
- public static void main(String[] args) {
- CommandManager commandMgr = new CommandManager();
- Receiver receiver = new Receiver();
- System.out.println("--- execute command ---");
- Command commandAaa = new ConcreteCommand(receiver, "aaa");
- commandMgr.executeCommand(commandAaa);
- Command commandBbb = new ConcreteCommand(receiver, "bbb");
- commandMgr.executeCommand(commandBbb);
- Command commandCcc = new ConcreteCommand(receiver, "ccc");
- commandMgr.executeCommand(commandCcc);
- Command commandDdd = new ConcreteCommand(receiver, "ddd");
- commandMgr.executeCommand(commandDdd);
- System.out.println(receiver.getData());
- System.out.println("-- undo ---");
- commandMgr.undoCommand();
- commandMgr.undoCommand();
- System.out.println(receiver.getData());
- }
- }
- /**
- * Command
- * abstract command class
- *
- */
- abstract class Command {
- protected Receiver receiver;
- protected String param;
- public Command(Receiver receiver, String expr) {
- this.receiver = receiver;
- this.param = expr;
- }
- abstract public void execute();
- }
- /**
- * UndoableCommand
- * abstract undo supportable command class which extends from Command class
- *
- */
- abstract class UndoableCommand extends Command {
- public UndoableCommand(Receiver receiver, String expr) {
- super(receiver, expr);
- }
- abstract public void undo();
- }
- /**
- * ConcreteCommand
- * concrete command class which extends from UndoableCommand
- *
- */
- class ConcreteCommand extends UndoableCommand {
- private String previousData = null;
- public ConcreteCommand(Receiver receiver, String expr) {
- super(receiver, expr);
- }
- @Override
- public void execute() {
- previousData = receiver.getData();
- receiver.append(this.param);
- }
- @Override
- public void undo() {
- receiver.setData(previousData);
- }
- }
- /**
- * CommandManager
- * Command Manager class which stack the exe
- *
- */
- class CommandManager {
- private Stack commandStack = new Stack();
- public void executeCommand(Command cmd) {
- cmd.execute();
- if (cmd instanceof UndoableCommand) {
- commandStack.push(cmd);
- }
- }
- public void undoCommand() {
- if (commandStack.size() > 0) {
- UndoableCommand cmd = (UndoableCommand) commandStack.pop();
- cmd.undo();
- } else {
- throw new UnsupportedOperationException("");
- }
- }
- }
- /**
- * Receiver
- * target object
- *
- */
- class Receiver {
- private String data = "";
- public void append(String expr) {
- data += expr;
- }
- public String getData() {
- return data;
- }
- public void setData(String data) {
- this.data = data;
- }
- }
- /**
- class Invoker {
- private Command command;
- public void setCommand(Command command) {
- this.command = command;
- }
- public void executeCommand() {
- command.execute();
- }
- }
- */
import java.util.Stack;
public class Client {
/**
* Test Command Pattern
*
*/
public static void main(String[] args) {
CommandManager commandMgr = new CommandManager();
Receiver receiver = new Receiver();
System.out.println("--- execute command ---");
Command commandAaa = new ConcreteCommand(receiver, "aaa");
commandMgr.executeCommand(commandAaa);
Command commandBbb = new ConcreteCommand(receiver, "bbb");
commandMgr.executeCommand(commandBbb);
Command commandCcc = new ConcreteCommand(receiver, "ccc");
commandMgr.executeCommand(commandCcc);
Command commandDdd = new ConcreteCommand(receiver, "ddd");
commandMgr.executeCommand(commandDdd);
System.out.println(receiver.getData());
System.out.println("-- undo ---");
commandMgr.undoCommand();
commandMgr.undoCommand();
System.out.println(receiver.getData());
}
}
/**
* Command
* abstract command class
*
*/
abstract class Command {
protected Receiver receiver;
protected String param;
public Command(Receiver receiver, String expr) {
this.receiver = receiver;
this.param = expr;
}
abstract public void execute();
}
/**
* UndoableCommand
* abstract undo supportable command class which extends from Command class
*
*/
abstract class UndoableCommand extends Command {
public UndoableCommand(Receiver receiver, String expr) {
super(receiver, expr);
}
abstract public void undo();
}
/**
* ConcreteCommand
* concrete command class which extends from UndoableCommand
*
*/
class ConcreteCommand extends UndoableCommand {
private String previousData = null;
public ConcreteCommand(Receiver receiver, String expr) {
super(receiver, expr);
}
@Override
public void execute() {
previousData = receiver.getData();
receiver.append(this.param);
}
@Override
public void undo() {
receiver.setData(previousData);
}
}
/**
* CommandManager
* Command Manager class which stack the exe
*
*/
class CommandManager {
private Stack commandStack = new Stack();
public void executeCommand(Command cmd) {
cmd.execute();
if (cmd instanceof UndoableCommand) {
commandStack.push(cmd);
}
}
public void undoCommand() {
if (commandStack.size() > 0) {
UndoableCommand cmd = (UndoableCommand) commandStack.pop();
cmd.undo();
} else {
throw new UnsupportedOperationException("");
}
}
}
/**
* Receiver
* target object
*
*/
class Receiver {
private String data = "";
public void append(String expr) {
data += expr;
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
}
/**
class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void executeCommand() {
command.execute();
}
}
*/
执行Client,输出结果:
C:/Command>java Client
--- execute command ---
aaabbbcccddd
-- undo ---
aaabbb
C:/Command>
我们可以看到,使用Command模式非常简单地就实现了undo操作。
最后
以上就是精明小懒虫为你收集整理的设计模式之Command - 命令模式的全部内容,希望文章能够帮你解决设计模式之Command - 命令模式所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复