1. 定义
命令模式是一个高内聚的模式,其定义为:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
命令模式
2. 使用场景
- 需要抽象出待执行的动作,然后以参数的形式提供出来。替代过程设计中的回调机制。
- 在不同的时刻指定、排列和执行请求。
- 需要支持事务操作、取消功能、日志功能。
- Android中的事件传递机制就使用到了命令模式。
3. 实现
以项目经理分别下发写代码、设计UI两条命令给程序员、视觉设计师为例子来实现命令模式。
接收者角色及其实现:
/**
* 接收者角色:该角色就是干活的角色,命令传递到这里是应该被执行的。
* 例子:程序员、视觉设计师的基类
*/
public abstract class Receiver {
public abstract void doSomething();
}
/**
* 例子:程序员
*/
public class ConcreteReceiver1 extends Receiver{
@Override
public void doSomething() {
System.out.println("写代码");
}
}
/**
* 例子:视觉设计师
*/
public class ConcreteReceiver2 extends Receiver{
@Override
public void doSomething() {
System.out.println("设计UI");
}
}
命令角色及其实现:
/**
* 命令角色:需要执行的所有命令都在这里声明。
*/
public abstract class Command {
protected Receiver mReceiver;
public Command(Receiver receiver) {
this.mReceiver = receiver;
}
public abstract void execute();
}
/**
* 例子:写代码的命令,下发给程序员
*/
public class ConcreteCommand1 extends Command {
public ConcreteCommand1() {
super(new ConcreteReceiver1());
}
public ConcreteCommand1(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
this.mReceiver.doSomething();
}
}
/**
* 例子:设计UI的命令,下发给视觉设计师
*/
public class ConcreteCommand2 extends Command {
public ConcreteCommand2() {
super(new ConcreteReceiver2());
}
public ConcreteCommand2(Receiver receiver) {
super(receiver);
}
@Override
public void execute() {
this.mReceiver.doSomething();
}
}
调用者角色:
/**
* 调用者角色:接收客户端的命令,并执行命令。
* 例子:项目经理
*/
public class Invoker {
private Command mCommand;
public void setCommand(Command command) {
this.mCommand = command;
}
public void action() {
this.mCommand.execute();
}
}
场景类:
public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
invoker.setCommand(new ConcreteCommand1());
invoker.action();
invoker.setCommand(new ConcreteCommand2());
invoker.action();
}
}
运行结果:
写代码
设计UI
4. 优点
- 类间解耦。调用者角色与接收者角色之间没有任何依赖关系,调用者实现功能时只需调用Command抽象类的execute方法就可以,不需要了解到底是哪个接收者执行。
- 可扩展性。Command的子类可以非常容易地扩展,而调用者Invoker和高层次的模块Client不产生严重的代码耦合。
- 命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题。
5. 缺点
- 命令模式如果有N个命令Command的子类就有N个,类数量膨胀得非常大。