概述
- 命令模式又称为行动(Action) 模式或交易(Transaction) 模式。
- 命令模式把一个请求或者操作封装到一个对象中。命令模式允许系统使用不同的请求把客户端参数化;对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
- 命令模式是对命令的封装。命令模式把命令的责任和执行命令的责任分割开,委派给不同的对象。
模式结构
示意性代码
namespace 命令模式
{
class Receiver
{
public void Action()
{
Console.WriteLine("操作成功!");
}
}
abstract class Command
{
protected Receiver receiver;
public Command(Receiver receiver)
{
this.receiver = receiver;
}
abstract public void Execute();
}
class ConcreteCommand:Command
{
public ConcreteCommand(Receiver receiver) : base(receiver) { }
public override void Execute()
{
receiver.Action();
}
}
class Invoker
{
private Command command;
public void SetCommand(Command command)
{
this.command = command;
}
public void ExecuteCommand()
{
command.Execute();
}
}
class Program
{
static void Main(string[] args)
{
Receiver r = new Receiver();
Command c = new ConcreteCommand(r);
Invoker i = new Invoker();
i.SetCommand(c);
i.ExecuteCommand();
Console.Read();
}
}
}
- 将请求的接收者(Receiver)放到Command的具体子类ConcreteCommand中,当请求到来时(Invoker发出Invoker消息激活Command对象),ConcreteCommand将处理请求交给Receiver对象进行处理
- Command模式将调用操作的对象和知道如何实现该操作的对象解耦。在上面Command的结构图中,Invoker对象根本就不知道具体的是哪个对象在处理Excute操作。
- 在Command下要增加新的处理操作对象很容易,我们可以通过创建新的继承自Command的子类来实现这一点。
- Command模式可以和Memento模式结合起来,支持Undo的操作。
使用命令模式情况
- 如果需要在不同的时刻指定、排列和执行请求,可以选用命令模式,把这些请求封装成为命令对象,然后实现把请求队列化
- 如果需要支持取消操作从可以选用命令模式,通过管理命令对象,,能很容易的实现命令的恢复和重做的功能
- 如果需要支持当系统崩溃时,能把对系统的操作功能重新执行一遍,可以选用命令模式,把这些操作功能的请求封装成命令对象,然后实现日志命令,就可以在系统恢复回来后,通过日志获取命令列表,从而重新执行一遍功能
- 在需要事务的系统中,可以选用命令模式,命令模式提供了对事务进行建模的方法,命令模式有二个别名就是Transaction.
优点
命令允许请求的一方和接收请求的一方能够独立演化。
- 命令模式使新的命令很容易地被加入到系统里
- 允许接收请求的一方决定是否要否决(Veto) 请求。
- 能较容易地设计一个命令队列。
- 可以容易地实现对请求的Undo和Redo。
- 在需要的情况下,可以较容易地将命令记入日志。
- 命令模式把请求一个 操作的对象与知道怎么执行一个操作的对象分割开。
- 命令类与其他任何别的类-样,可以修改和推广。
本质
封装请求。
实例
ps:代码仅代表个人思路
【问题】使用命令模式设计一个简易计算器
【代码】
public abstract class Command {
abstract public void execute();
abstract public void unExcute();
}
public class CalculatorCommand extends Command {
private char operator;
private int operand;
private Calculator calculator;
public CalculatorCommand() {}
public CalculatorCommand(char operator, int operand, Calculator calculator) {
super();
this.operator = operator;
this.operand = operand;
this.calculator = calculator;
}
public void setOperator(char operator) {
this.operator = operator;
}
public void setOperand(int operand) {
this.operand = operand;
}
public void setCalculator(Calculator calculator) {
this.calculator = calculator;
}
@Override
public void execute() {
calculator.operation(operator,operand);
}
@Override
public void unExcute() {
if(calculator.getNum()!=0) {
calculator.operation(undo(operator), operand);
calculator.setNum(calculator.getNum()-2);
}
}
private char undo(char operator) {
switch (operator) {
case '+':
operator='-';
break;
case '-':
operator='+';
break;
case '*':
operator='/';
break;
case '/':
operator='*';
break;
}
return operator;
}
}
public class Calculator {
private int total = 0;
private int num = 0;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public void operation(char operator, int operand) {
if (num == 0) {
num++;
total = operand;
} else {
switch (operator) {
case '+':
total += operand;
num++;
break;
case '-':
total -= operand;
num++;
break;
case '*':
total *= operand;
num++;
break;
case '/':
total /= operand;
num++;
break;
}
}
System.out.println("Total="+total);
}
}
public class User {
private Calculator calculator=new Calculator();
private Command[] commands=new Command[10000000];
private int current=0;
public void redo(int levels) {
for(int i=0;i<levels;i++) {
if(current<commands.length-1) {
commands[current++].execute();
}
}
}
public void undo(int levels) {
for(int i=0;i<levels;i++) {
if(current>0) {
commands[--current].unExcute();
}
}
}
public void compute(char operator ,int operand) {
Command command=new CalculatorCommand(operator,operand,calculator);
command.execute();
commands[current++]=command;
}
}
public class Client {
public static void main(String[] args) {
User user =new User();
user.compute('+', 100);
user.compute('-', 50);
user.compute('*', 10);
user.compute('/', 2);
user.undo(4);
user.redo(3);
}
}
【UML图】