设计模式:命令(Command) in java

定义:命令模式是一种高内聚的模式。它将一个请求封装成一个对象,从而让使用不同请求来把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销与恢复功能。
听起来,好复杂!

在程序员之间,流传着这样一句话:程序写到最后,就是if-else,for,while。
真是枯燥啊!其实能体会到这种感觉,说明作为一个程序员,你已经有了一定的造诣了。那如何提高呢?

试想,在代码中,你有很多if-else或者case语句。为什么有这样的语句呢?因为判断条件多啊,需要根据不同的条件来做不同的事情。2、3个条件还可以写,如果有20个条件呢,或者N多呢。那么我们的if-else那就判断N重条件,这简直是无法忍受的,写出的代码可维护性更不用说了。

命令模式就是可以解决这种问题的方法之一。下面就来提高一下程序员的自我修养了。

命令模式中,主要有3个角色:

  • Receiver命令接收者
  • Command命令
  • Invoker命令调用者

下面开始分别定义:
**Receiver:**定义命令的N种接收者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public abstract class AbstractReceiver {
public abstract void doSomething();
}

public class Receiver1 extends AbstractReceiver {
@Override
public void doSomething() {
System.out.println("receiver1 do something");
}
}
public class Receiver2 extends AbstractReceiver {
@Override
public void doSomething() {
System.out.println("receiver2 do something");
}
}
...
public class ReceiverN
...

**Command:**定义N种命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public abstract class AbstractCommand {
public abstract void execute();
}

public class Command1 extends AbstractCommand {
private AbstractReceiver receiver;
public Command1(AbstractReceiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println("command1 命令发出");
receiver.doSomething();
}
}
public class Command2 extends AbstractCommand {
private AbstractReceiver receiver;
public Command2(AbstractReceiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
System.out.println("command2 命令发出");
receiver.doSomething();
}
}
...
public class CommandN
....

**Invoker:**定义调用者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Invoker {

private List<AbstractCommand> commandList = new LinkedList<AbstractCommand>();

public void addCommand(AbstractCommand command) {
commandList.add(command);
}

public void addCommands(LinkedList<AbstractCommand> commands) {
commandList.addAll(commands);
}

public void action() {
for (AbstractCommand command : commandList) {
command.execute();
}
}

}

使用场景:

1
2
3
4
5
6
7
8
Invoker invoker = new Invoker();
AbstractReceiver receiver1 = new Receiver1();
AbstractReceiver receiver2 = new Receiver2();
AbstractCommand command1 = new Command1(receiver2);
AbstractCommand command2 = new Command2(receiver1);
invoker.addCommand(command1);
invoker.addCommand(command2);
invoker.action();

运行结果:

1
2
3
4
command1 命令发出
receiver2 do something
command2 命令发出
receiver1 do something

现在再回过来看命令模式的定义,就比较明白了吧。也就是说有N种请求条件,那么就定义N个类来封装请求,我们称之为命令(Command)。每个命令做什么操作呢,谁来执行这个命令呢,有命令自己来进行定义。这样就避免了if-else,而由N种命令来决定跳转关系。

调用者(Invoker)呢,它维护了一个命令列表,并按照一定的顺序来发起命令调用。当然这个列表也有可能就只有一个命令了,就简化了一下。与if-else对比更直观的了。

定义中还提到了命令撤销或恢复的功能,这种撤销与恢复也是命令的一种了,一般可以通过扩展一个命令出来,通过诸如日志等来恢复之前的操作。其实这个也是可以通过备忘录模式来实现的。

命令模式 in JDK

1
2
java.lang.Runnable#run()
javax.swing.Action#actionPeformed(ActionEvent e)

从Runnable来说,不同的实现者,通过调用run()来实现在不同线程执行不同的操作。
从Action来说,由于桌面UI有很多的操作事件,这些事件就是命令。通过actionPerformed函数,接受不同的命令参数来做出不同的表现。