道滘镇网站建设,房屋经纪人网站端口怎么做,个性化定制平台,网站建设需要注意的C指挥家#xff1a;掌控命令模式之美 (C Conductor: Master the Beauty of Command Pattern一、引言 (Introduction)1.1 命令模式概述 (Overview of Command Pattern)1.2 命令模式的应用场景 (Application Scenarios of Command Pattern)二、命令模式的基本概念 (Basic Concep…
C指挥家掌控命令模式之美 (C Conductor: Master the Beauty of Command Pattern一、引言 (Introduction)1.1 命令模式概述 (Overview of Command Pattern)1.2 命令模式的应用场景 (Application Scenarios of Command Pattern)二、命令模式的基本概念 (Basic Concepts of Command Pattern)2.1 接收者Receiver2.2 命令Command2.3 调用者Invoker2.4 具体命令Concrete Command2.5 命令模式UML图三、C实现命令模式 (Implementing Command Pattern in C)3.1 设计接收者类 (Designing the Receiver Class)3.2 设计命令接口 (Designing the Command Interface)3.3 实现具体命令类 (Implementing the Concrete Command Classes)四、命令模式的优缺点 (Pros and Cons of Command Pattern)4.1 命令模式的优点 (Advantages of Command Pattern)4.2 命令模式的缺点 (Disadvantages of Command Pattern)五、命令模式的应用实例 (Application Examples of Command Pattern)5.1 图形编辑器 (Graphic Editor)5.2 播放器控制 (Player Control)六、结语一、引言 (Introduction)
1.1 命令模式概述 (Overview of Command Pattern)
命令模式Command Pattern是一种行为型设计模式主要用于将请求发送者和请求接收者解耦。该模式涉及四个角色接收者Receiver、命令Command、调用者Invoker和具体命令Concrete Command。命令模式的核心思想是将请求封装成对象从而实现对操作的高度灵活性。
Command Pattern is a behavioral design pattern that primarily decouples the request sender and the request receiver. It involves four roles: Receiver, Command, Invoker, and Concrete Command. The core idea of the command pattern is to encapsulate requests into objects, thereby achieving high flexibility for operations.
1.2 命令模式的应用场景 (Application Scenarios of Command Pattern)
命令模式适用于以下几种场景
当需要将请求发送者和请求接收者解耦时可以使用命令模式。这使得调用者和接收者之间的联系变得更加松散增强了系统的灵活性。当需要实现对请求的撤销、重做或者存储请求操作历史记录等功能时命令模式可以为你提供帮助。当系统需要支持一组可配置的操作时命令模式可以实现动态地组合操作和修改操作顺序。当系统需要实现异步操作或者需要将操作放入队列中进行处理时命令模式也很适用。
Command pattern is suitable for the following scenarios:
When you need to decouple the request sender and request receiver, you can use the command pattern. This makes the connection between the caller and the receiver more relaxed, enhancing the flexibility of the system.When you need to implement undo, redo, or store request operation history, the command pattern can help you.When the system needs to support a set of configurable operations, the command pattern can dynamically combine and modify operation orders.When the system needs to implement asynchronous operations or needs to put operations into a queue for processing, the command pattern is also very suitable.
二、命令模式的基本概念 (Basic Concepts of Command Pattern)
2.1 接收者Receiver
接收者Receiver是命令模式中负责执行具体操作的对象。它包含了所有操作的具体实现方法。通常情况下接收者与命令本身是分离的它们之间不直接交互。
Receiver is the object responsible for executing specific operations in the Command Pattern. It contains all the specific implementation methods of the operations. Generally, the receiver is separate from the command itself, and they do not interact directly.
2.2 命令Command
命令Command是一个抽象类或接口它定义了一个名为execute()的方法该方法接受一个接收者Receiver实例作为参数。命令对象用于封装执行某个操作的请求将请求与实际的操作解耦。
Command is an abstract class or interface that defines a method called execute(), which takes a Receiver instance as a parameter. The command object is used to encapsulate a request to perform an operation, decoupling the request from the actual operation.
2.3 调用者Invoker
调用者Invoker负责发起请求和执行命令。它包含了一个或多个命令对象并且在需要时触发命令对象的execute()方法。调用者不需要关心命令的具体实现只需要知道如何发起请求。
Invoker is responsible for initiating requests and executing commands. It contains one or more command objects and triggers the execute() method of the command object when needed. The invoker does not need to care about the specific implementation of the command, it only needs to know how to initiate a request.
2.4 具体命令Concrete Command
具体命令Concrete Command是命令接口的具体实现。每一个具体命令都包含了一个接收者Receiver实例该实例负责执行与该命令相关的操作。当调用者触发execute()方法时具体命令将调用接收者的相应方法以完成实际操作。
Concrete Command is the specific implementation of the Command interface. Each concrete command contains a Receiver instance responsible for performing the operation associated with the command. When the invoker triggers the execute() method, the concrete command will call the corresponding method of the receiver to complete the actual operation.
2.5 命令模式UML图
命令模式的UML图包含以下几个关键部分
Command抽象命令一个接口或抽象类定义了execute()方法。ConcreteCommand具体命令实现Command接口的具体类实现了execute()方法并持有Receiver的引用。Receiver接收者执行具体操作的类包含具体操作的实现方法。Invoker调用者持有Command对象的类负责发起请求和执行命令。
以下是命令模式的UML图
------------------- ------------------- --------------------
| Invoker | | Command | | Receiver |
------------------- ------------------- --------------------
| setCommand(cmd) |-----| execute() : void |-----| action() : void |
| executeCommand() | ------------------- --------------------
------------------- ^ ^| |------------------ ---------------| ConcreteCommand | | SpecificReceiver |------------------ ---------------| execute() : void | | action() : void |------------------ ---------------在此UML图中Invoker类通过setCommand()方法设置ConcreteCommand对象并通过executeCommand()方法触发ConcreteCommand对象的execute()方法。ConcreteCommand类实现了Command接口并在其execute()方法中调用Receiver类的具体操作。具体的Receiver类包含了操作的实现方法。
三、C实现命令模式 (Implementing Command Pattern in C)
3.1 设计接收者类 (Designing the Receiver Class)
首先我们需要设计一个接收者类这个类包含了具体操作的实现方法。在本例中我们将创建一个名为Light的类它有一个turnOn()方法来表示开灯操作一个turnOff()方法表示关灯操作。
#include iostreamclass Light {
public:void turnOn() {std::cout Light is on. std::endl;}void turnOff() {std::cout Light is off. std::endl;}
};在这个例子中Light类代表接收者Receiver负责执行与开灯和关灯相关的操作。
3.2 设计命令接口 (Designing the Command Interface)
接下来我们需要定义一个命令接口。在C中我们可以使用抽象类来表示接口。我们将创建一个名为Command的抽象类其中包含一个纯虚函数execute()。
class Command {
public:virtual void execute() 0;
};3.3 实现具体命令类 (Implementing the Concrete Command Classes)
现在我们需要为每个具体操作创建具体命令类。在本例中我们需要创建两个具体命令类TurnOnLightCommand和TurnOffLightCommand。这两个类都继承自Command抽象类并实现execute()方法。每个具体命令类都包含一个Light对象的引用用于执行实际的操作。
class TurnOnLightCommand : public Command {
private:Light light;public:TurnOnLightCommand(Light light) : light(light) {}void execute() override {light.turnOn();}
};class TurnOffLightCommand : public Command {
private:Light light;public:TurnOffLightCommand(Light light) : light(light) {}void execute() override {light.turnOff();}
};在这个例子中我们通过构造函数将Light对象的引用传递给具体命令类使得具体命令类能够执行实际操作。TurnOnLightCommand类实现了execute()方法调用light.turnOn()而TurnOffLightCommand类实现了execute()方法调用light.turnOff()。
四、命令模式的优缺点 (Pros and Cons of Command Pattern)
4.1 命令模式的优点 (Advantages of Command Pattern)
解耦请求发送者与请求接收者命令模式将请求发送者Invoker与请求接收者Receiver解耦使它们之间的联系变得更加松散有助于系统的灵活性和可扩展性。易于扩展新命令使用命令模式时如果需要添加新的操作只需要实现一个新的具体命令类即可无需修改已有的代码。支持撤销、重做等操作命令模式可以轻松地实现撤销、重做等功能。通过存储已执行的命令对象并实现相应的撤销和重做方法可以实现这些功能。支持将命令放入队列和异步执行命令模式可以将多个命令放入队列中进行处理。此外它还可以支持异步操作将操作放入后台线程中执行。
4.2 命令模式的缺点 (Disadvantages of Command Pattern)
增加了系统的复杂性命令模式引入了许多新的类如抽象命令类、具体命令类等。这使得系统的复杂性增加增加了学习和理解的难度。可能导致类数量过多由于每个操作都需要一个具体命令类所以当有大量操作时可能导致类数量急剧增加使系统变得庞大和难以维护。增加了间接性命令模式将请求发送者与接收者之间增加了一个抽象层次。这虽然带来了一定程度的解耦但也增加了系统的间接性可能导致调试和定位问题更加困难。
尽管命令模式有一些缺点但在合适的场景下它仍然是一种非常有用的设计模式。在需要解耦发送者和接收者、易于扩展新命令或支持撤销、重做等功能的系统中命令模式是一个很好的选择。
五、命令模式的应用实例 (Application Examples of Command Pattern)
5.1 图形编辑器 (Graphic Editor)
首先我们创建一个简化版的图形编辑器实现如下功能添加圆形、删除圆形、打印当前图形。
#include iostream
#include vector
#include memory // C11特性: shared_ptr
#include algorithm // C14特性: std::find_if, std::remove_if
#include any // C17特性: std::anyclass Circle {
public:Circle(int id) : id(id) {}void draw() const {std::cout Draw circle with ID: id std::endl;}int getID() const {return id;}private:int id;
};class GraphicEditor {
public:void addCircle(std::shared_ptrCircle circle) {circles.push_back(circle);}void removeCircle(int id) {circles.erase(std::remove_if(circles.begin(), circles.end(),[id](const auto circle) { return circle-getID() id; }), // C14特性: auto, lambda expressioncircles.end());}void printCircles() const {std::cout Current circles: std::endl;for (const auto circle : circles) { // C11特性: auto, range-based for loopcircle-draw();}}private:std::vectorstd::shared_ptrCircle circles;
};现在我们将使用命令模式重构图形编辑器。
// Command Interface
class Command {
public:virtual ~Command() default; // C11特性: 默认函数defaultvirtual void execute() 0;
};// Concrete Command: AddCircleCommand
class AddCircleCommand : public Command {
public:AddCircleCommand(GraphicEditor editor, int id) : editor(editor), circle(std::make_sharedCircle(id)) {} // C14特性: std::make_sharedvoid execute() override {editor.addCircle(circle);}private:GraphicEditor editor;std::shared_ptrCircle circle;
};// Concrete Command: RemoveCircleCommand
class RemoveCircleCommand : public Command {
public:RemoveCircleCommand(GraphicEditor editor, int id) : editor(editor), id(id) {}void execute() override {editor.removeCircle(id);}private:GraphicEditor editor;int id;
};// Invoker: CommandHandler
class CommandHandler {
public:void setCommand(std::shared_ptrCommand command) {this-command command;}void executeCommand() {if (command) {command-execute();}}private:std::shared_ptrCommand command;
};int main() {GraphicEditor editor;CommandHandler handler;auto addCircleCommand std::make_sharedAddCircleCommand(editor, 1);auto removeCircleCommand std::make_sharedRemoveCircleCommand(editor, 1);handler.setCommand(addCircleCircleCommand);handler.executeCommand(); // 添加圆形editor.printCircles(); // 输出: Draw circle with ID: 1handler.setCommand(addCircleCommand);handler.executeCommand(); // 再次添加圆形editor.printCircles(); // 输出: Draw circle with ID: 1, Draw circle with ID: 1handler.setCommand(removeCircleCommand);handler.executeCommand(); // 删除圆形editor.printCircles(); // 输出: Draw circle with ID: 1std::any userData; // C17特性: std::anyuserData 42;std::cout UserData: std::any_castint(userData) std::endl; // 输出: UserData: 42return 0;}
在上面的代码中我们使用了命令模式重构了简化版的图形编辑器并展示了如何添加和删除圆形。同时我们使用了C11C14和C17的特性如shared_ptrautolambda expressionmake_sharedany等并提供了详细注释。
5.2 播放器控制 (Player Control)
首先我们创建一个简化版的播放器
#include iostream
#include memory // C11特性: shared_ptr
#include any // C17特性: std::any
#include optional // C17特性: std::optionalclass Player {
public:void play() {std::cout Playing... std::endl;}void pause() {std::cout Paused. std::endl;}void stop() {std::cout Stopped. std::endl;}
};现在我们将使用命令模式重构播放器控制
// Command Interface
class Command {
public:virtual ~Command() default; // C11特性: 默认函数defaultvirtual void execute() 0;
};// Concrete Command: PlayCommand
class PlayCommand : public Command {
public:explicit PlayCommand(Player player) : player(player) {} // C11特性: explicit关键字void execute() override {player.play();}private:Player player;
};// Concrete Command: PauseCommand
class PauseCommand : public Command {
public:explicit PauseCommand(Player player) : player(player) {}void execute() override {player.pause();}private:Player player;
};// Concrete Command: StopCommand
class StopCommand : public Command {
public:explicit StopCommand(Player player) : player(player) {}void execute() override {player.stop();}private:Player player;
};// Invoker: RemoteController
class RemoteController {
public:void setCommand(std::shared_ptrCommand command) {this-command command;}void pressButton() {if (command) {command-execute();}}private:std::shared_ptrCommand command;
};int main() {Player player;RemoteController remote;auto playCommand std::make_sharedPlayCommand(player);auto pauseCommand std::make_sharedPauseCommand(player);auto stopCommand std::make_sharedStopCommand(player);remote.setCommand(playCommand);remote.pressButton(); // 输出: Playing...remote.setCommand(pauseCommand);remote.pressButton(); // 输出: Paused.remote.setCommand(stopCommand);remote.pressButton(); // 输出: Stopped.// C17特性: std::optionalstd::optionalint maybeValue;if (!maybeValue.has_value()) { // 当前没有值maybeValue 42;}if (maybeValue.has_value()) { // 现在有值了std::cout Optional value: maybeValue.value() std::endl; // 输出: Optional value: 42}return 0;
}六、结语
在本篇博客中我们详细介绍了C中命令模式的概念、原理、优缺点以及在图形编辑器和播放器控制中的应用。通过学习命令模式我们不仅可以提高自己的编程技巧还可以更好地理解面向对象设计原则提升编程思维。
从心理学角度来看学习和理解设计模式对个人和团队都具有积极意义。首先设计模式提供了一种解决问题的共同语言有助于团队成员之间的有效沟通降低沟通成本。其次设计模式可以提高程序员的自信心因为它们代表了行业内公认的最佳实践。使用设计模式可以使程序员确信自己的解决方案是高效、稳定的从而提高工作满意度。
此外学习设计模式有助于培养程序员的创新思维。了解现有的设计模式可以帮助我们站在巨人的肩膀上以更高的起点开始思考问题。在学习和理解现有设计模式的基础上我们可以更好地发现潜在的设计问题甚至可能提出新的设计模式。
总之本篇博客通过深入浅出的介绍和示例让读者更好地理解和掌握命令模式。从心理学角度看学习命令模式不仅有助于提高编程技能还可以促进团队协作激发创新思维。希望本篇博客能给您带来启发和收获祝您学习愉快