命令模式(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. 命令模式与其他模式对比

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

总结

  • 适用场景: 当需要参数化请求、支持撤销操作、记录操作日志时,适合使用命令模式。
  • 优点: 解耦发送者和接收者,支持撤销与恢复操作,扩展性强。
  • 注意事项: 不要因滥用模式而增加系统复杂度,仅在需要时使用。
目录
打赏
0
7
7
0
18
分享
相关文章
|
7月前
|
Modbus协议深入解析
Modbus协议是由Modicon公司(现施耐德电气)于1979年发明的串行通信协议,主要用于工业自动化系统中的PLC通信。本文深入解析了Modbus协议的主从模式、数据类型(线圈、离散输入、保持寄存器、输入寄存器)、帧结构和通信过程,并介绍了其应用场景和重要性。
296 0
|
7月前
|
建造者模式详解
建造者模式是一种创建型设计模式,通过将对象的构造与表示分离,使得同样的构建过程可以创建不同的对象。它适用于复杂对象的构建,如汽车制造、软件配置生成等场景。该模式的核心角色包括抽象建造者、具体建造者、产品和指挥者。优点包括解耦构造和表示、代码复用性强、易于扩展;缺点是增加代码复杂度,对产品组成部分有依赖。
164 3
|
7月前
|
责任链模式(Chain of Responsibility Pattern)
责任链模式是一种行为型设计模式,允许多个对象按顺序处理请求,直到某个对象处理为止。适用于多个对象可能处理同一请求的场景,如请假审批流程。优点是灵活性高、降低耦合,但责任链过长可能影响性能。
176 3
代理模式(Proxy Pattern)
代理模式(Proxy Pattern)是一种设计模式,通过一个中间对象(代理)来间接访问目标对象,以控制访问权限或添加额外功能。常见的代理类型包括远程代理、虚拟代理、保护代理和智能引用代理。代理模式常用于延迟加载、权限控制、日志记录等场景,能够提高系统的灵活性和安全性。
216 3
UML中类图的介绍与使用
类图是 UML 中用于展示系统静态结构的重要工具,包括类、接口及其关系。类图有助于系统可视化、团队沟通、发现设计问题、文档化系统和辅助开发工具。类图的三大元素是类、接口和关系,其中关系又细分为关联、聚合、组合、继承、实现和依赖。类图在设计模式学习和实际开发中非常重要,许多现代 IDE 都支持从类图生成代码或从代码生成类图。
367 2
|
7月前
|
适配器模式(Adapter Pattern)
适配器模式是一种结构型设计模式,通过将一个类的接口转换为客户期望的另一个接口,使原本接口不兼容的类可以一起工作。它包括目标接口、适配者和适配器三个核心角色。适配器模式常用于解决旧系统兼容性问题、第三方库整合和统一接口等场景。该模式有类适配器和对象适配器两种实现方式,分别通过继承和组合实现。适配器模式的优点包括提高兼容性、遵循开闭原则和灵活性高,但也存在适配器数量增加导致复杂性和可能影响性能的缺点。
256 1
策略模式(Strategy Pattern)
策略模式(Strategy Pattern)是一种行为型设计模式,允许在运行时选择算法或行为,而不是在编译时确定。通过将具体算法封装成独立的类,并通过统一接口与客户端交互,实现算法的动态替换,避免代码重复和复杂条件语句。适用于支付方式切换、导航路径选择等场景。
212 1
|
7月前
|
工厂方法模式
工厂方法模式是一种创建型设计模式,定义一个创建对象的接口,但让子类决定具体实例化哪个类。该模式具有高内聚、低耦合的特点,支持动态扩展新产品类型,适用于复杂或经常变化的产品族。其主要组成部分包括抽象产品、具体产品、抽象工厂和具体工厂。工厂方法模式遵循开闭原则,新增产品无需修改现有代码,但会增加系统复杂性。
74 5
观察者模式
观察者模式是一种行为型设计模式,用于定义对象间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。该模式主要用于实现发布-订阅机制。核心角色包括主题(Subject)、观察者(Observer)、具体主题(Concrete Subject)和具体观察者(Concrete Observer)。优点包括低耦合、动态添加观察者和自动更新,但也有可能引起过多更新、不适合同步通知和可能造成内存泄漏等缺点。适用于气象站数据更新、股票价格监控和用户界面组件更新等场景。
121 4
单例模式详解
单例模式是一种常用的创建型设计模式,确保某个类只有一个实例,并提供一个全局访问点。本文详细介绍了单例模式的定义、特点、适用场景、优缺点及实现代码(C++ 和 C#),并探讨了线程安全的实现细节和与依赖注入的结合使用。
152 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问