命令模式

命令模式将”请求“封装成对象,以便使用不同的请求、队列、或者日志来参数化其他对象。命令模式也可支持可撤销的操作。

一个命令对象通过在特定接收者上绑定一组动作来封装一个请求。也就是说:命令对象将动作和接收者包进对象中,这个对象只暴露出一个execute方法,当execute方法被调用的时候,接收者就会进行这些动作,从外面来看,其他对象不知道究竟哪个接收者进行了哪些动作,只知道调用了execute方法目的就达到了。

 

image.png

 

 

命令模式类图如图所示:

Client:负责创建一个ConcreteCommand,并设置其接收者。

Invoker:这个调用者持有一个命令对象,并在某个时间点调用命令对象的execute()方法,将请求付诸行动。

Command为所有命令声明了一个接口,调用命令对象的execute方法,就可以让接收者进行相关动作。

ConcreteCommand: 该类定义了动作和接收者之间的绑定关系。调用者只要调用execute接口就可以发出请求,然后由ConcreteCommand调用接收者的一个或多个动作。

Receiver:接收者知道如何进行必要的工作,实现这个请求。任何类都可以当接收者。

 

命令模式uml2.png       

 

代码示例:

receiver:

public interface Light {
   public void on();

   public void off();
}

 

public class KitchenLight implements Light{
   public void on(){
      System.out.println("KitchenLight light on.");
   }
   public void off(){
      System.out.println("KitchenLight light off.");
   }
}

 

public class LivingRoomLight implements Light{
   public void on(){
      System.out.println("LivingRoomLight light on.");
   }
   public void off(){
      System.out.println("LivingRoomLight light off.");
   }
}

 

public class GarageDoor {
   public void open(){
      System.out.println("This door is open");
   }

   public void close(){
      System.out.println("This door is closed");
   }
}

 

Command:

public interface Command {
   public void execute();
}

 

ConcreteCommand:

public class LightOnCommand implements Command {
   Light light;

   public LightOnCommand( Light light){
      this.light = light;
   }

   @Override
   public void execute() {
      light.on();
   }
}

 

public class LightOffCommand implements Command {
   Light light ;
   public LightOffCommand(Light light){
      this.light = light;
   }

   @Override
   public void execute() {
      light.off();
   }
}

 

public class GarageDoorOpen implements Command {
   GarageDoor garageDoor;
   public GarageDoorOpen(GarageDoor garageDoor){
      this.garageDoor = garageDoor;
   }

   @Override
   public void execute() {
      garageDoor.open();
   }
}

 

public class GarageDoorClose implements Command {
   GarageDoor garageDoor;
   public GarageDoorClose(GarageDoor garageDoor){
      this.garageDoor = garageDoor;
   }

   @Override
   public void execute() {
      garageDoor.close();
   }
}

 

Invoker:

public class SimpleRemoteControl {
   Command slot;
   public  SimpleRemoteControl(){}

   public void setCommand(Command command){
      this.slot = command;
   }

   public void buttonWasPressed(){
      slot.execute();
   }
}

 

命令模式调用方式:

 

 

Client:

public class RemoteControlTest {
   public static void main(String[] args){
    //创建发起者       SimpleRemoteControl remote = new SimpleRemoteControl();
    //封装具体命令者       LightOnCommand lightOnCommand = new LightOnCommand(new LivingRoomLight());
    //设置即将使用的具体命令者       remote.setCommand(lightOnCommand);
    //发出指令       remote.buttonWasPressed();
      lightOnCommand = new LightOnCommand(new KitchenLight());       remote.setCommand(lightOnCommand);       remote.buttonWasPressed();       GarageDoorOpen garageDoorOpen = new GarageDoorOpen(new GarageDoor());       remote.setCommand(garageDoorOpen);       remote.buttonWasPressed();    } }

 

测试结果:

LivingRoomLight light on.

KitchenLight light on.

This door is open

 

使用lambda表达式可以省去具体的命令者类的创建。

在setCommand时候,直接传入接口Command的execute的具体实现,execute的具体实现通过lambda表达式和接收者的动作完成。

事实上,具体创建的命令者如 LightOnCommand,也就是重写了Command的execute接口。

复制代码

public class RemoteControlTest {
public static void main(String[] args){
SimpleRemoteControl remote = new SimpleRemoteControl();
LivingRoomLight livingRoomLight = new LivingRoomLight();
remote.setCommand(()->livingRoomLight.on());
remote.buttonWasPressed();

KitchenLight kitchenLight = new KitchenLight();
remote.setCommand(()->kitchenLight.on());
remote.buttonWasPressed();

GarageDoor garageDoor = new GarageDoor();
remote.setCommand(()->garageDoor.open());
remote.buttonWasPressed();
}
}
复制代码

 测试结果:

LivingRoomLight light on.
KitchenLight light on.
This door is open

 命令模式也可以理解为,通过命令控制中心,将命令发出,然后由具体的执行者执行。

命令控制中心SimpleRemoteControl设置命令(Command),然后命令控制中心下发指令后,Command开始工作并调用execute方法,execute方法执行的是命令接收者的某个方法。 

这里有个生活中的示例我们可以想象一下,就是小爱同学或者天猫精灵的使用。我们跟小爱同学说:“小爱同学,把空调打开”,小爱同学接受到这个命令后,识别了两个信息,“空调”和“打开”。 假如它内部没有纳管空调,也就是没有在它设备中没有添加空调,这个时候可能回复说:"抱歉,主人,没有找到空调,无法操作"。 如果有空调,可能临时就建造了一个命令对象Command,该对象内部的接收者是空调,动作是打开。随后它就加载这个命令对象到通过控制中心,控制中心执行打开操作,那最后这个空调就打开了。

posted @   小兵要进步  阅读(60)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)

侧边栏
点击右上角即可分享
微信分享提示