命令模式(Command)是指,把请求封装成一个命令,然后执行该命令。

    在使用命令模式前,我们先以一个编辑器为例子,看看如何实现简单的编辑操作:

    我们用一个模拟一个文本编辑器,它支持copy()paste()add()delete()等方法。

    正常情况,我们像这样调用TextEditor

    1. TextEditor editor = new TextEditor();
    2. editor.add("Command pattern in text editor.\n");
    3. editor.copy();
    4. editor.paste();
    5. System.out.println(editor.getState());

    这是直接调用方法,调用方需要了解TextEditor的所有接口信息。

    如果改用命令模式,我们就要把调用方发送命令和执行方执行命令分开。怎么分?

    1. public interface Command {
    2. void execute();
    3. }

    调用方创建一个对应的Command,然后执行,并不关心内部是如何具体执行的。

    为了支持CopyCommandPasteCommand这两个命令,我们从Command接口派生:

    最后我们把CommandTextEditor组装一下,客户端这么写:

    1. TextEditor editor = new TextEditor();
    2. editor.add("Command pattern in text editor.\n");
    3. // 执行一个CopyCommand:
    4. Command copy = new CopyCommand(editor);
    5. editor.add("----\n");
    6. // 执行一个PasteCommand:
    7. Command paste = new PasteCommand(editor);
    8. paste.execute();

    这就是命令模式的结构:

    1. ┌──────┐ ┌───────┐
    2. Client│─ ─>│Command
    3. └──────┘ └───────┘
    4. ┌──────────────┐
    5. ├─>│ CopyCommand
    6. ├──────────────┤
    7. editor.copy() │─
    8. └──────────────┘
    9. ┌────────────┐
    10. ┌──────────────┐ ─>│ TextEditor
    11. └─>│ PasteCommand └────────────┘
    12. ├──────────────┤
    13. editor.paste()│─
    14. └──────────────┘

    有的童鞋会有疑问:搞了一大堆Command,多了好几个类,还不如直接这么写简单:

    实际上,使用命令模式,确实增加了系统的复杂度。如果需求很简单,那么直接调用显然更直观而且更简单。

    答案是视需求而定。如果TextEditor复杂到一定程度,并且需要支持Undo、Redo的功能时,就需要使用命令模式,因为我们可以给每个命令增加undo()

    1. public interface Command {
    2. void execute();
    3. void undo();

    然后把执行的一系列命令用List保存起来,就既能支持Undo,又能支持Redo。这个时候,我们又需要一个Invoker对象,负责执行命令并保存历史命令:

    1. ┌─────────────┐
    2. Client
    3. ┌─────────────┐
    4. Invoker
    5. ├─────────────┤ ┌───────┐
    6. List commands│─ ─>│Command
    7. invoke(c) └───────┘
    8. undo() ┌──────────────┐
    9. └─────────────┘ ├─>│ CopyCommand
    10. ├──────────────┤
    11. editor.copy() │─
    12. └──────────────┘
    13. ┌────────────┐
    14. ┌──────────────┐ ─>│ TextEditor
    15. └─>│ PasteCommand └────────────┘
    16. ├──────────────┤
    17. editor.paste()│─
    18. └──────────────┘

    可见,模式带来的设计复杂度的增加是随着需求而增加的,它减少的是系统各组件的耦合度。

    给命令模式新增Add和Delete命令并支持Undo、Redo操作。

    从下载练习:命令模式练习 (推荐使用快速下载)

    命令模式的设计思想是把命令的创建和执行分离,使得调用者无需关心具体的执行过程。

    命令 - 图1