命令模式(Command)----设计模式
命令模式,简单的讲,就是将**“命令动作的请求者"和"命令动作的执行者”**进行解耦,并要求请求可以撤销的。
生活中也处处可见命令模式:
老板发布一个命令,不是直接发布到了员工手中,而是发布给了秘书,具体怎么执行这个命令,交给秘书来完成;再或者一个多用遥控器,上面有很多的家用电器的开关按钮,此时你就可以通过这一个遥控器操控所有电器,而具体电器的开关不与你直接相关…
什么是命令模式?
命令模式(Command Pattern),在软件设计中,我们经常需要向某些对象发送请求,但是具体不知道请求的接收者是谁,也不知道被请求的操作是哪一个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来设计。
命令模式使得请求发送者与请求接收者消除彼此之间得耦合,让对象之间的调用关系更加灵活,实现解耦。
在命令模式中,会将一个请求封装为一个对象,以便使用不同参数来表示不同的请求(即命令),同时命令模式也支持撤销操作。
应该会有小伙伴们感觉到迷糊,其实最初我也很迷糊的,下面一会让我们看个具体的多用遥控器的实现过程可能就清楚啦~
命令模式中的几个部分
-
Command:
定义命令的接口,声明执行的方法。
-
ConcreteCommand(以下demo中,电灯、电视的开关动作都为此类):
命令接口实现对象,是“虚”的实现;通常会持有接收者,并调用接收者的功能来完成命令要执行的操作。
-
Receiver(电灯LightRecever、电视类TVRecever):
接收者,真正执行命令的对象。任何类都可能成为一个接收者,只要它能够实现命令要求实现的相应功能。
通常聚合在ConcreteCommand中。
-
Invoker(RemoteController遥控器):
要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。
-
Client:
创建具体的命令对象,并且设置命令对象的接收者。注意这个不是我们常规意义上的客户端,而是在组装命令对象和接收者,或许,把这个Client称为装配者会更好理解,因为真正使用命令的客户端是从Invoker来触发执行。
命令模式的类图
多用遥控器案例实现
command接口
package com.design_patterns.command;
//创建命令接口
public interface Command {
//执行动作(操作)
public void execute();
//撤销动作(操作)
public void undo();
}
LightOnCommand电灯打开执行类
package com.design_patterns.command;
public class LightOnCommand implements Command {
private LightReceiver lightReceiver;
//构造方法
public LightOnCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
//聚合LightReceiver
@Override
public void execute() {
//调用接收者的方法
lightReceiver.on();
}
@Override
public void undo() {
//调用接收者的方法
lightReceiver.off();
}
}
LightOffCommand电灯关闭执行类
package com.design_patterns.command;
public class LightOffCommand implements Command {
private LightReceiver lightReceiver;
//构造方法
public LightOffCommand(LightReceiver lightReceiver) {
this.lightReceiver = lightReceiver;
}
//执行关闭的方法
@Override
public void execute() {
this.lightReceiver.off();
}
//执行撤销命令
@Override
public void undo() {
this.lightReceiver.on();
}
}
TVOnCommand电视机打开执行类
package com.design_patterns.command;
public class TVOnCommand implements Command {
//聚合tv接收者
private TVReceiver tvReceiver;
//通过构造方法传递进来实际的tv接收者
public TVOnCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
//使接收者执行动作命令
this.tvReceiver.on();
}
@Override
public void undo() {
//撤回操作
this.tvReceiver.off();
}
}
NoCommand无命令类,用于初始化操作
package com.design_patterns.command;
/**
* 无任何命令,即空执行。
* 用于初始化每个按钮,当调用空命令时,对象什么都不做
* 其实,这样也是一种设计模式,可以省略对空命令的判断
*/
public class NoCommand implements Command {
@Override
public void execute() {
}
@Override
public void undo() {
}
}
TVOffCommand电视机关闭执行类
package com.design_patterns.command;
public class TVOffCommand implements Command {
private TVReceiver tvReceiver;
public TVOffCommand(TVReceiver tvReceiver) {
this.tvReceiver = tvReceiver;
}
@Override
public void execute() {
this.tvReceiver.off();
}
@Override
public void undo() {
this.tvReceiver.on();
}
}
LightReceiver电灯接收者类
package com.design_patterns.command;
public class LightReceiver {
public void on(){
System.out.println("电灯打开了!");
}
public void off(){
System.out.println("电灯关闭了!");
}
}
TVReceiver电视接收者类
package com.design_patterns.command;
public class TVReceiver {
public void on(){
System.out.println("电视TV打开了!");
}
public void off(){
System.out.println("电视TV关闭了!");
}
}
RemoteController发出请求的invoker多用遥控器类
package com.design_patterns.command;
public class RemoteController {
//开 按钮的命令数组
Command[] onCommands;
Command[] offCommands;
//执行撤销的命令
Command undoCommand;
public RemoteController() {
onCommands = new Command[5];
offCommands = new Command[5];
for (int i = 0; i < 5; i++){
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
//为我们的按钮设置你所需要的命令
public void setCommand(int no, Command onCommand, Command offCommand){
onCommands[no] = onCommand;
offCommands[no] = offCommand;
}
//按下开的按钮
public void onButtonWasPushed(int no){
// 找到你按下的按钮,并调用对应的方法
onCommands[no].execute();
//记录这次的操作,用于撤销
undoCommand = onCommands[no];
}
//按下关的按钮
public void offButtonWasPushed(int no){
// 找到你按下的按钮,并调用对应的方法
offCommands[no].execute();
//记录这次的操作,用于撤销
undoCommand = offCommands[no];
}
//按下撤销按钮
public void undoButtonWasPush(){
//撤销上次的动作
undoCommand.undo();
}
}
Client客户端
package com.design_patterns.command;
import javafx.scene.effect.Light;
public class Client {
public static void main(String[] args) {
//使用命令设计模式,完成通过遥控器,对电灯的操作
/**
* 创建电灯的对象(接收者)
*/
LightReceiver lightReceiver = new LightReceiver();
//创建电灯相关的开关命令
LightOnCommand lightOnCommand = new LightOnCommand(lightReceiver);
LightOffCommand lightOffCommand = new LightOffCommand(lightReceiver);
//创建一个遥控器
RemoteController remoteController = new RemoteController();
//给我们的遥控器设置相关的命令,比如 no = 0 使电灯的开和关的操作
remoteController.setCommand(0,lightOnCommand,lightOffCommand);
System.out.println("----按下灯的开的按钮----");
remoteController.onButtonWasPushed(0);
System.out.println("----按下灯的关的按钮----");
remoteController.offButtonWasPushed(0);
System.out.println("----撤销的操作----");
remoteController.undoButtonWasPush();
/**
* 创建电视TV的对象(接收者)
*/
TVReceiver tvReceiver = new TVReceiver();
//创建电视TV相关的开关命令
TVOnCommand tvOnCommand = new TVOnCommand(tvReceiver);
TVOffCommand tvOffCommand = new TVOffCommand(tvReceiver);
//给我们的遥控器设置相关的命令,比如 no = 1 使用电视TV的开和关的操作
remoteController.setCommand(1,tvOnCommand,tvOffCommand);
System.out.println("----按下电视TV的开的按钮----");
remoteController.onButtonWasPushed(1);
System.out.println("----按下电视TV的关的按钮----");
remoteController.offButtonWasPushed(1);
System.out.println("----撤销的操作----");
remoteController.undoButtonWasPush();
}
}
运行结果
----按下灯的开的按钮----
电灯打开了!
----按下灯的关的按钮----
电灯关闭了!
----撤销的操作----
电灯打开了!
----按下电视TV的开的按钮----
电视TV打开了!
----按下电视TV的关的按钮----
电视TV关闭了!
----撤销的操作----
电视TV打开了!
总结
命令模式最主要的功能就是实现了请求端与执行端的分离,通过一个请求对象来接收请求,调用执行端执行操作,同样命令模式也实现了动作的撤销操作,更加提高了程序的健壮性。
好啦,这就是命令模式,如果有小伙伴们不理解,欢迎下方留言评论~