一、模式定义
命令模式将请求封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象,命令模式支持可撤销的操作。
命令模式可以使发送者和接受者完全解耦,发送者与接收者之间并没有直接的联系,发送者只需要知道如何发送请求,不需要关心请求是如何完成的,这就是命令模式,命令模式将方法调用给封装起来了。
有点CallBack的意思,主要的三个角色就是“下命令的对象”、“命令对象”、“执行命令的对象”,三者互相解耦,不需要知道彼此具体实现。
二、模式结构
从上图可以看出命令模式包含如下几个角色:
Command: 抽象命令类
ConcreteCommand: 具体命令类
Invoker: 调用者
Receiver: 接收者
Client:客户类
命令模式的本质就在于将命令进行封装,将发出命令的责任和执行命令的责任分开,使得发送者只需要知道如何发送命令即可,不需要知道命令是如何实现的,甚至命令执行是否成功都不需要理会。同时命令模式使得请求也变成了一个对象,它像其他对象一样可以被存储和传递。
三、模式实现
用一个小明让老板加工资的栗子来说明这个模式:
/** * 接收者 */public class Boss { /** * 处理"加薪"命令 */ public void addSalary(){ System.out.println("公司董事会商议决定的,让boss给员工加工资."); } /** * 不处理"加薪"命令(取消命令) */ public void cancelSalary(){ System.out.println("公司董事会经过商讨, 做出如下艰难的决定:暂时不让boss给员工加工资."); } }
/** * 规定了用于封装"请求"的方法及撤销命令的方法 */public interface Command { /** * 封装"请求"的方法 */ public abstract void execute(); /** * 撤销"命令" */ public abstract void undo();}
/** * 具体命令 */public class ConcreteCommand implements Command{ private Boss receiver;//接收者 public ConcreteCommand(Boss receiver){ this.receiver = receiver; } @Override public void execute() { //封装"请求" receiver.addSalary(); //加工资 } @Override public void undo() { receiver.cancelSalary();//取消加工资 }}
/** * 请求者 */public class XiaoMing { private Command command; public XiaoMing(Command command) { this.command = command; } /** * 让具体命令执行execute()方法 */ public void startExecuteCommand() { command.execute(); } /** * 让具体命令执行undo()方法 */ public void undoCommand(){ command.undo(); } }
/** * 使用命令模式 */public class Application { public static void main(String[] args) { //创建接收者 Boss receiver = new Boss(); //创建具体命令并制定接收者 Command command = new ConcreteCommand(receiver); //创建请求者 XiaoMing invoker = new XiaoMing(command); invoker.startExecuteCommand(); invoker.undoCommand(); }}
公司董事会商议决定的,让boss给员工加工资.公司董事会经过商讨, 做出如下艰难的决定:暂时不让boss给员工加工资.
四、使用场景
1.系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
2.系统需要在不同的时间指定请求、将请求排队和执行请求。
3.系统需要支持命令的撤销(Undo)操作和恢复(Redo)操作。
4.系统需要将一组操作组合在一起,即支持宏命令