基本介绍
我们日常的开发就很好地体现出了命令模式,比如:领导将开发任务指派给程序员去完成。其中领导就是“命令的发布者(调用者)”,程序员就是“命令的具体执行者(接收者)”,这个指派的动作就是“具体的命令”。命令将调用者和接收者进行连接,从而完成开发任务,这一套流程就可以看作是命令模式的执行原理。
命令模式使得请求的发送者与请求的执行者之间消除耦合,让对象之间的调用关系更加灵活。在命令模式中,会将一个命令封装成一个对象,同时命令模式也支持可撤销的操作。
命令模式UML类图
UML类图讲解
Invoker:调用者角色。
Command:抽象命令角色,封装了所有需要执行的命令,可以是抽象类或接口。
Receiver:接收者角色,具体执行命令的类。
ConcreteCommand:具体命令角色,实现了Command类,并聚合了Receiver类。该类的作用是将一个接收者对象与一个命令进行绑定。
案例讲解
通过上面的介绍相信大家对命令模式模式有了一个简单的认识,下面让我们通过一个案例来加深对该模式的理解。
案例:实现通过遥控器开关电视以及撤销上一次操作的功能。
命令接口 => 对应抽象命令角色
public interface Command {
// 执行操作
void execute();
// 撤销操作
void undo();
}
电视 => 对应接收者角色
public class TVReceiver {
public void on() {
System.out.println("电视机打开了。");
}
public void off() {
System.out.println("电视机关闭了。");
}
}
具体命令实现类
/**
* 开电视
*/
public class TVOnCommand implements Command {
// 聚合TVReceiver
private TVReceiver tv;
public TVOnCommand(TVReceiver tv) {
this.tv = tv;
}
@Override
public void execute() {
// 执行打开电视机命令
this.tv.on();
}
@Override
public void undo() {
// 执行关闭电视机命令,因为打开电视对应的就是关闭。
this.tv.off();
}
}
/**
* 关闭电视
*/
public class TVOffCommand implements Command {
// 聚合TVReceiver
private TVReceiver tv;
public TVOffCommand(TVReceiver tv) {
this.tv = tv;
}
@Override
public void execute() {
// 执行关闭电视机命令
this.tv.off();
}
@Override
public void undo() {
// 执行打开电视机命令,因为关闭电视机对应的就是打开。
this.tv.on();
}
}
/**
* 空命令
* 该类默认实现Command接口,不执行任何命令。添加该类的作用是
* 为了省略执行操作时对空的判断。
*/
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
遥控器 => 对应调用者角色
public class RemoteController {
// 开按钮的命令
private Command onCommand = new NoCommand();
// 关按钮的命令
private Command offCommand = new NoCommand();
// 执行撤销的命令
private Command undoCommand = new NoCommand();
// 给按钮设置相关命令
public void setCommand(Command onCommand, Command offCommand) {
this.onCommand = onCommand;
this.offCommand = offCommand;
}
// 按下打开按钮
public void onButtonWasPushed() {
this.onCommand.execute();
// 记录本次操作
this.undoCommand = this.onCommand;
}
// 按下关闭按钮
public void offButtonWasPushed() {
this.offCommand.execute();
// 记录本次操作
this.undoCommand = this.offCommand;
}
// 按下撤销按钮
public void undoButtonWasPushed() {
this.undoCommand.undo();
}
}
客户端测试类
public class Client {
public static void main(String[] args) {
// 创建电视机接收者
TVReceiver tvReceiver = new TVReceiver();
// 创建电视机开关命令
TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
// 创建遥控器
RemoteController remoteController = new RemoteController();
// 设置命令
remoteController.setCommand(tvOnCommand, tvOffCommand);
System.out.println("======按下打开按钮======");
remoteController.onButtonWasPushed();
System.out.println("======按下关闭按钮======");
remoteController.offButtonWasPushed();
System.out.println("======撤销上次操作======");
remoteController.undoButtonWasPushed();
}
}
执行结果
总结
优点
1、调用者只需要调用命令对象的“执行”方法就可以让接收者工作,而不必知道具体是谁接收的命令,命令是如何被执行的。将发起命令请求的对象和执行命令的对象拆分开从而促使代码解耦,通过这样的设计将利于程序的扩展。
2、通过添加一个“空命令”来省去判空的操作。
3、通过添加撤销方法可以实现对命令的撤销重做。
缺点:
造成系统存在过多的具体命令类,增加系统的复杂度。
注意
命令对象负责让具体的接收者执行指定的操作,它就是连接“请求发起者”和“请求执行者”的桥梁。
今天的分享就到这里了,如果感觉“菜鸟”写的文章还不错,记得点赞加关注呦!你们的支持就是我坚持下去的动力。文章哪里写的有问题的也希望大家可以指出,我会虚心受教。