命令模式将请求发送者与请求接受者解耦,请求发送者通过命令对象来间接引用接收者,使得系统具有更好的灵活性。 可以再不修改现有系统源代码的情况下将相同的发送者对应不同的接受者,也可以将多个命令对象组合成宏命令,还可以在命令类中提供用来撤销请求的方法。
定义
将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作模式或事务模式。
本质
命令模式的本质是对命令进行封装,将发出命令的责任和执行命令的责任分割开。每一个命令都是一个操作:请求的一方发出请求,要求执行一个操作;接受的一方收到请求,并执行操作。命令模式允许请求的一方和接收的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收、操作是否被执行、何时被执行,以及是怎么被执行的。
案例
某软件公司欲开发一个基于Windows平台的公告板系统。系统提供一个主菜单(Menu),在主菜单中包含了一些菜单项(MenuItem),可以通过Menu类的addMenuItem()方法增加菜单项。菜单项的主要方法是click(),每一个菜单项包含一个抽象命令类,具体命令类包括OpenCommand(打开命令),CreateCommand(新建命令),EditCommand(编辑命令)等,命令类具有一个execute()方法,用于调用公告板系统界面类(BoardScreen)的open()、create()、edit()等方法。现使用命令模式设计该系统,使得MenuItem类与BoardScreen类的耦合度降低。
类图如下:
代码如下:
public class BoardScreen {
void open(){
System.out.println("打开");
}
void edit(){
System.out.println("编辑");
}
void create(){
System.out.println("创建");
}
}
public abstract class Command {
abstract void execute();
}
public class OpenCommand extends Command {
private BoardScreen bs;
public OpenCommand(){
bs=new BoardScreen();
}
@Override
public void execute() {
bs.open();
}
}
public class CreateCommand extends Command {
private BoardScreen bs;
public CreateCommand(){
bs=new BoardScreen();
}
@Override
public void execute() {
bs.create();
}
}
public class EditCommit extends Command {
private BoardScreen bs;
public EditCommit(){
bs=new BoardScreen();
}
@Override
public void execute() {
bs.edit();
}
}
public class Menu {
private Command openCommand;
private Command editCommand;
private Command createCommand;
public Menu(OpenCommand openCommand,EditCommit editCommand,CreateCommand createCommand){
this.openCommand=openCommand;
this.editCommand=editCommand;
this.createCommand=createCommand;
}
public void open(){
openCommand.execute();
}
public void edit(){
editCommand.execute();
}
public void create(){
createCommand.execute();
}
}
测试代码:
public class Main {
public static void main(String[] args) {
Menu m=new Menu(new OpenCommand(),new EditCommit(),new CreateCommand());
m.create();
m.edit();
m.open();
}
}
测试结果:
结论
通过命令模式可以使得调用者和接受者不直接交互。请求调用者无需知道接受者的是谁,接受者也无需关心何时被调用。