命令模式(Command Pattern)

简介: 命令模式是一种行为型设计模式,将请求封装为对象,实现参数化请求、支持撤销操作和记录日志。适用于需要解耦发送者和接收者的场景,如智能家居系统中的遥控器控制电灯开关并支持撤销功能。优点包括解耦、支持撤销与恢复操作,但过度使用会增加系统复杂度。

命令模式(Command Pattern)详解

1. 定义

命令模式是一种行为型设计模式,它将一个请求封装为一个对象,从而使得可以用不同的请求对客户进行参数化、对请求排队或记录日志,以及支持可撤销的操作。

通俗解释:

将操作(请求)抽象成独立的对象,从而分离请求的发送者和接收者,允许轻松添加、修改和管理请求。


2. 组成部分

组件 描述
Command(命令接口) 定义命令执行的接口或抽象类,封装命令的行为。
ConcreteCommand 具体命令类,绑定一个接收者并实现具体的操作。
Receiver(接收者) 执行命令的实际逻辑对象。
Invoker(调用者) 调用命令对象的接口,发送请求。
Client(客户端) 创建具体命令对象并将其关联到调用者和接收者。

3. 使用场景

使用场景 描述
需要参数化方法调用 命令模式将行为抽象为对象,方便动态指定行为。
需要支持撤销或恢复操作 通过存储命令对象的状态,实现撤销和恢复功能。
需要记录操作日志 将命令的执行过程记录,方便后续分析或回滚。
需要解耦发送者与接收者 客户端只需操作命令对象,无需关心具体的操作逻辑。

4. 优点与缺点

优点 缺点
解耦性高:将请求发送者与接收者分离。 增加系统复杂度:每个操作都需要创建命令类。
扩展性强:可以方便地新增命令。 命令对象可能过多:复杂系统中命令类数量可能增加。
支持撤销和恢复:便于实现操作历史管理。 性能开销:需要额外的内存存储命令对象。

5. 使用案例

示例描述:

一个智能家居系统,包括电灯和电视,可以通过遥控器控制它们的开关,并支持撤销功能。


C++ 示例

#include <iostream>
#include <stack>
using namespace std;

// 接收者:灯
class Light {
public:
   void on() {
       cout << "Light is ON" << endl;
   }
   void off() {
       cout << "Light is OFF" << endl;
   }
};

// 命令接口
class Command {
public:
   virtual void execute() = 0;
   virtual void undo() = 0;
   virtual ~Command() {}
};

// 具体命令:打开灯
class LightOnCommand : public Command {
private:
   Light* light;
public:
   LightOnCommand(Light* l) : light(l) {}
   void execute() override {
       light->on();
   }
   void undo() override {
       light->off();
   }
};

// 具体命令:关闭灯
class LightOffCommand : public Command {
private:
   Light* light;
public:
   LightOffCommand(Light* l) : light(l) {}
   void execute() override {
       light->off();
   }
   void undo() override {
       light->on();
   }
};

// 调用者:遥控器
class RemoteControl {
private:
   Command* command;
   stack<Command*> history;
public:
   void setCommand(Command* cmd) {
       command = cmd;
   }
   void pressButton() {
       if (command) {
           command->execute();
           history.push(command);
       }
   }
   void pressUndo() {
       if (!history.empty()) {
           Command* cmd = history.top();
           cmd->undo();
           history.pop();
       }
   }
};

// 客户端代码
int main() {
   Light light;
   LightOnCommand lightOn(&light);
   LightOffCommand lightOff(&light);

   RemoteControl remote;
   remote.setCommand(&lightOn);
   remote.pressButton(); // 打开灯
   remote.pressUndo();   // 撤销打开灯

   remote.setCommand(&lightOff);
   remote.pressButton(); // 关闭灯
   remote.pressUndo();   // 撤销关闭灯

   return 0;
}


C# 示例

using System;
using System.Collections.Generic;

// 接收者:灯
class Light {
   public void On() {
       Console.WriteLine("Light is ON");
   }
   public void Off() {
       Console.WriteLine("Light is OFF");
   }
}

// 命令接口
interface ICommand {
   void Execute();
   void Undo();
}

// 具体命令:打开灯
class LightOnCommand : ICommand {
   private Light light;
   public LightOnCommand(Light light) {
       this.light = light;
   }
   public void Execute() {
       light.On();
   }
   public void Undo() {
       light.Off();
   }
}

// 具体命令:关闭灯
class LightOffCommand : ICommand {
   private Light light;
   public LightOffCommand(Light light) {
       this.light = light;
   }
   public void Execute() {
       light.Off();
   }
   public void Undo() {
       light.On();
   }
}

// 调用者:遥控器
class RemoteControl {
   private ICommand command;
   private Stack<ICommand> history = new Stack<ICommand>();

   public void SetCommand(ICommand command) {
       this.command = command;
   }

   public void PressButton() {
       command?.Execute();
       history.Push(command);
   }

   public void PressUndo() {
       if (history.Count > 0) {
           ICommand cmd = history.Pop();
           cmd.Undo();
       }
   }
}

// 客户端代码
class Program {
   static void Main(string[] args) {
       Light light = new Light();
       ICommand lightOn = new LightOnCommand(light);
       ICommand lightOff = new LightOffCommand(light);

       RemoteControl remote = new RemoteControl();
       remote.SetCommand(lightOn);
       remote.PressButton(); // 打开灯
       remote.PressUndo();   // 撤销打开灯

       remote.SetCommand(lightOff);
       remote.PressButton(); // 关闭灯
       remote.PressUndo();   // 撤销关闭灯
   }
}


命令模式的类图

6. 命令模式与其他模式对比

特性 命令模式 策略模式
核心作用 将请求封装为独立对象,支持撤销和记录功能。 定义一系列算法,将其封装并相互替换。
解耦性 解耦发送者和接收者。 解耦算法的使用和实现。
适用场景 需要对操作进行封装或扩展。 需要动态选择算法或行为。

总结

  • 适用场景: 当需要参数化请求、支持撤销操作、记录操作日志时,适合使用命令模式。
  • 优点: 解耦发送者和接收者,支持撤销与恢复操作,扩展性强。
  • 注意事项: 不要因滥用模式而增加系统复杂度,仅在需要时使用。
目录
相关文章
|
设计模式 语音技术
设计模式12 - 命令模式【Command Pattern】
设计模式12 - 命令模式【Command Pattern】
59 0
|
设计模式 数据库
命令模式(Command Pattern)
命令模式(Command Pattern)是一种行为型设计模式,它将请求或操作封装成对象,以便于使用不同的请求、队列或日志来参数化其他对象。命令模式可以将命令的请求者和执行者解耦,从而增强系统的灵活性和可扩展性。
103 2
|
存储 Java 程序员
行为型模式 - 命令模式(Command Pattern)
行为型模式 - 命令模式(Command Pattern)
命令模式(Command)
请求发送者与接收者解耦——命令模式(一)请求发送者与接收者解耦——命令模式(二)请求发送者与接收者解耦——命令模式(三)请求发送者与接收者解耦——命令模式(四)请求发送者与接收者解耦——命令模式(五)请求发送者与接收者解耦——命令模式(六) ...
679 0
|
开发工具 git 人工智能
|
开发工具 git 人工智能
|
C# 设计模式 程序员
C#设计模式(15)——命令模式(Command Pattern)
原文:C#设计模式(15)——命令模式(Command Pattern) 一、前言   之前一直在忙于工作上的事情,关于设计模式系列一直没更新,最近项目中发现,对于设计模式的了解是必不可少的,当然对于设计模式的应用那更是重要,可以说是否懂得应用设计模式在项目中是衡量一个程序员的技术水平,因为对于一个功能的实现,高级工程师和初级工程师一样都会实现,但是区别在于它们实现功能的可扩展和可维护性,也就是代码的是否“优美”、可读。
1155 0

热门文章

最新文章