定义
将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化,对请求排队或者记录请求日志,以及支持可撤销操作。
本质
封装请求
登场角色
-
Command(命令)
负责定义命令的接口
-
ConcreteCommand(具体的命令)
实现命令接口
-
Receiver(接收者)
命令接收者,真正执行命令的对象,任何对象都可以成为命令接收者,只要它能够实现命令要求实现的相应功能。
-
Client(请求者)
创建具体的命令对象并设置命令接收者,即组装命令对象和接收者。
-
Invoker(发动者)
开始执行命令的角色。通常持有命令对象,可以持有很多命令对象,相当于命令对象的入口。
示例代码
/**
* 接收者角色,处理具体逻辑
* 是整个命令模式中唯一处理具体代码逻辑的地方,
* 其他的类都是直接或间接的调用到该类的方法
*/
public class TerisMachine {
/**
* 真正处理向左操作的逻辑
*/
public void toLeft(){
System.out.println("向左");
}
/**
* 真正处理向右操作的逻辑
*/
public void toRight(){
System.out.println("向右");
}
/**
* 真正处理快速落下操作的逻辑
*/
public void fastToBottom(){
System.out.println("快速落下");
}
/**
* 真正处理改变形状操作的逻辑
*/
public void transform(){
System.out.println("改变形状");
}
}
/**
* 命令抽象者
*/
public interface Command {
void execute();
}
/**
* 具体命令,持有一个接收者角色对象
*/
public class LeftCommand implements Command{
private TerisMachine terisMachine;
public LeftCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}
@Override
public void execute() {
terisMachine.toLeft();
}
}
/**
* 具体的命令
*/
public class RightCommand implements Command{
private TerisMachine terisMachine;
public RightCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}
@Override
public void execute() {
terisMachine.toRight();
}
}
/**
* 具体的命令
*/
public class FallCommand implements Command{
private TerisMachine terisMachine;
public FallCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}
@Override
public void execute() {
terisMachine.fastToBottom();
}
}
/**
* 具体的命令
*/
public class TransforCommand implements Command{
private TerisMachine terisMachine;
public TransforCommand(TerisMachine terisMachine) {
this.terisMachine = terisMachine;
}
@Override
public void execute() {
terisMachine.transform();
}
}
/**
* 请求者
*/
public class Buttons {
private LeftCommand leftCommand;
private RightCommand rightCommand;
private FallCommand fallCommand;
private TransforCommand transforCommand;
public void setLeftCommand(LeftCommand leftCommand) {
this.leftCommand = leftCommand;
}
public void setRightCommand(RightCommand rightCommand) {
this.rightCommand = rightCommand;
}
public void setFallCommand(FallCommand fallCommand) {
this.fallCommand = fallCommand;
}
public void setTransforCommand(TransforCommand transforCommand) {
this.transforCommand = transforCommand;
}
public void toLeft(){
leftCommand.execute();
}
public void toRight(){
rightCommand.execute();
}
public void fall(){
fallCommand.execute();
}
public void transform(){
transforCommand.execute();
}
}
public class Client {
public static void main(String[] args){
//构造俄罗斯方块游戏
TerisMachine terisMachine = new TerisMachine();
//构造四种命令
LeftCommand leftCommand = new LeftCommand(terisMachine);
RightCommand rightCommand = new RightCommand(terisMachine);
FallCommand fallCommand = new FallCommand(terisMachine);
TransforCommand transforCommand = new TransforCommand(terisMachine);
//按钮可以执行不同的命令
Buttons buttons = new Buttons();
buttons.setLeftCommand(leftCommand);
buttons.setRightCommand(rightCommand);
buttons.setFallCommand(fallCommand);
buttons.setTransforCommand(transforCommand);
//具体按下哪个按钮玩家说了算
buttons.toLeft();
buttons.toRight();
buttons.fall();
buttons.transform();
}
}
运行结果
向左
向右
快速落下
改变形状
优点
-
更松散的耦合
命令模式使得发起命令的对象(客户端),和具体的命令的对象(接收者)对象完全解耦,也就是说发起命令的对象完全不知道具体实现对象是谁,也不知道如何实现。
-
更动态的控制
命令模式把请求封装起来,可以动态的对它进行参数化、队列化和日志化等操作,从而使得系统更加灵活。
-
很自然的复合命令
命令模式中的命令对象能够很容易的组合成复合命令,也就是前面讲的宏命令,从而使系统操作更简单,功能更强大。
-
更好的扩展性
由于发起命令的对象和具体的实现完全解耦,因此扩展新的命令就很容易,只需要实现新的命令对象,然后在装配的时候,把具体的实现对象设置到命令对象中,然后就可以使用这个命令对象,已有的实现完全不用变化。
何时使用
- 需要抽象出待执行的动作,然后以参数的形式提供出来。类似于过程设计中的回调机制,而命令模式正式回调机制的一个面向对象的替代品。
- 在不同的时候指定、排列和执行请求。一个命令对象可以有与初始请求无关的生命期。
- 需要支持取消操作。
- 支持修改日志功能,这样当系统崩溃时,这些修改可以被重做一次。
- 需要支持事务操作。
网友评论