突破编程_C++_设计模式(命令模式)

这篇具有很好参考价值的文章主要介绍了突破编程_C++_设计模式(命令模式)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

1 命令模式的基本概念

C++ 命令模式是一种设计模式,它允许将请求封装为一个对象,从而可以用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。命令模式的主要目的是将请求封装为对象,从而可以使用不同的请求把客户端与接收者解耦。

在命令模式中,通常包含以下几个关键角色:

(1)命令(Command): 这是一个抽象类,它声明了执行操作的接口。具体的命令类会实现这个接口,并绑定到一个接收者对象上。当命令对象被调用时,它会调用接收者的相应操作。

(2)具体命令(ConcreteCommand): 这是命令接口的具体实现类,它持有一个接收者对象,并实现了命令接口中的执行方法。当执行方法被调用时,它会调用接收者的相应方法来完成请求的操作。

(3)请求者(Invoker): 请求者负责调用命令对象的执行方法。它不需要知道具体的命令对象类型,只需要知道它是一个命令对象即可。

(4)接收者(Receiver): 接收者对象知道如何执行请求的操作。它具体实现了请求的功能。

2 命令模式的实现步骤

命令模式的实现步骤如下:

(1)定义命令接口:

  • 创建一个抽象类(或接口),声明一个执行操作的方法。这个方法将是所有具体命令类共有的接口。

(2)实现具体命令类:

  • 创建具体命令类,继承自命令接口。
  • 在具体命令类中,通常包含一个指向接收者对象的指针(或引用)。
  • 实现执行操作的方法,该方法内部调用接收者对象的相应方法来完成请求的操作。

(3)创建接收者类:

  • 定义一个接收者类,它包含实际执行操作的逻辑。
  • 接收者类的方法对应于命令类需要执行的操作。

(4)创建请求者类:

  • 请求者类负责调用命令对象的执行方法。
  • 请求者不需要知道具体的命令对象类型,它只需要持有一个命令对象的指针(或引用)。
  • 请求者类可以存储多个命令对象,并按照需要调用它们的执行方法。

(5)将命令对象与接收者对象关联:

  • 在创建具体命令对象时,将接收者对象传递给命令对象,以便命令对象在执行时可以调用接收者的方法。

(6)使用命令模式:

  • 在客户端代码中,创建接收者对象。
  • 创建与接收者对象关联的具体命令对象。
  • 将命令对象传递给请求者对象。
  • 请求者对象调用命令对象的执行方法,从而间接调用接收者的方法,完成请求的操作。

如下为样例代码:

#include <iostream>  
#include <memory>  
#include <string>  
#include <vector>  

// 创建接收者类  
class Receiver {
public:
	void action() {
		std::cout << "Receiver::action() called" << std::endl;
	}
};

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

// 实现具体命令类  
class ConcreteCommand : public Command {
public:
	ConcreteCommand(std::shared_ptr<Receiver> receiver) : m_receiver(receiver) {}
	void execute() override {
		m_receiver->action();
	}
private:
	std::shared_ptr<Receiver> m_receiver;
};

// 创建请求者类  
class Invoker {
public:
	void setCommand(std::unique_ptr<Command> command) {
		commands.push_back(std::move(command));
	}

	void executeCommands() {
		for (auto& cmd : commands) {
			cmd->execute();
		}
	}

private:
	std::vector<std::unique_ptr<Command>> commands;
};

// 客户端代码  
int main() 
{
	// 创建接收者对象  
	std::shared_ptr<Receiver> receiver = std::make_shared<Receiver>();

	// 创建具体命令对象,并与接收者对象关联  
	std::unique_ptr<Command> command = std::make_unique<ConcreteCommand>(receiver);

	// 创建请求者对象,并将命令对象传递给请求者  
	Invoker invoker;
	invoker.setCommand(std::move(command));

	// 请求者调用命令对象的执行方法  
	invoker.executeCommands(); // 输出: Receiver::action() called  

	return 0;
}

上面代码的输出为:

Receiver::action() called

在这个示例中:

  • Command 是一个抽象类,定义了命令的接口。
  • ConcreteCommand 是 Command 的具体实现,它持有一个指向 Receiver 的 shared_ptr,并在 execute 方法中调用 Receiver 的 action 方法。
  • Receiver 是接收者类,包含了实际要执行的操作。
  • Invoker 是请求者类,它持有一个 Command 对象的列表,并提供了一个方法来执行这些命令。

在 main 函数中,创建了 Receiver 对象和 ConcreteCommand 对象,并将 Receiver 对象传递给 ConcreteCommand 对象。然后将 ConcreteCommand 对象传递给 Invoker 对象,并调用 Invoker 的 executeCommands 方法来执行命令。最终,Receiver 的 action 方法被调用,输出了相应的信息。

3 命令模式的应用场景

C++命令模式的应用场景广泛,主要适用于以下情况:

(1)当功能需要支持撤销和恢复撤销操作时: 命令模式通过封装命令对象,可以方便地记录和执行命令历史,从而支持撤销和恢复撤销操作。这在图形编辑、文本编辑等应用中非常有用,例如,在绘制图形时,用户可以撤销最近的操作以返回到之前的状态。

(2)当需要设计一组命令,并且命令之间可以相互组合时: 命令模式支持将多个命令组合成一个复合命令,从而可以一次性执行多个操作。这在需要执行一系列相关操作时非常有用,例如,在编辑器中,用户可能希望将多个编辑操作(如剪切、复制、粘贴)组合成一个宏命令,以便一次性执行。

(3)当系统需要将命令发起者和命令执行者解耦时: 命令模式允许将请求封装为命令对象,从而使发送请求的对象和执行请求的对象解耦。这使得发送请求的对象不需要知道请求如何被完成,增加了系统的灵活性和可维护性。例如,在用户界面和后台逻辑之间,命令模式可以确保它们之间的松耦合,使得修改其中一方不会影响到另一方。

(4)当系统需要在不同时间指定、排列和执行请求时: 命令模式允许将命令对象存储在队列或列表中,然后根据需要按顺序执行它们。这对于实现批量操作、延迟执行或任务调度等功能非常有用。

总的来说,C++命令模式适用于需要解耦请求发送者和请求执行者、支持撤销操作、需要组合多个命令或在不同时间执行请求的场景。它能够提高系统的灵活性、可维护性和可扩展性。

3.1 命令模式应用于需要支持撤销和恢复撤销操作的场景

在 C++ 中,命令模式特别适用于需要支持撤销和恢复撤销操作的场景,如下为样例代码:

#include <iostream>  
#include <memory>  
#include <vector>  
#include <stack>  
#include <string>  

// 接收者类  
class Receiver {
public:
	std::string action() {
		std::string currentState = "New state"; // 假设这是某种状态  
		// 执行一些操作...  
		return currentState;
	}

	void restore(const std::string& state) {
		// 恢复到之前的状态...  
		std::cout << "Restoring to state: " << state << std::endl;
	}
};

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

// 具体命令类  
class ConcreteCommand : public Command {
public:
	ConcreteCommand(std::shared_ptr<Receiver> receiver) : receiver(receiver) {}

	void execute() override {
		previousState = receiver->action();
		std::cout << "Command executed: " << previousState << std::endl;
	}

	void undo() override {
		receiver->restore(previousState);
		std::cout << "Command undone: " << previousState << std::endl;
	}

private:
	std::shared_ptr<Receiver> receiver;
	std::string previousState;
};

// 撤销管理器  
class UndoManager {
public:
	void executeCommand(std::shared_ptr<Command> cmd) {
		cmd->execute();
		commands.push(cmd);
	}

	void undoLastCommand() {
		if (!commands.empty()) {
			auto cmd = commands.top();
			commands.pop();
			cmd->undo();
		}
		else {
			std::cout << "No commands to undo." << std::endl;
		}
	}

private:
	std::stack<std::shared_ptr<Command>> commands;
};

int main() 
{
	// 创建接收者对象  
	auto receiver = std::make_shared<Receiver>();

	// 创建命令对象  
	auto command = std::make_shared<ConcreteCommand>(receiver);

	// 创建撤销管理器  
	UndoManager undoManager;

	// 执行命令  
	undoManager.executeCommand(command);

	// 撤销命令  
	undoManager.undoLastCommand();

	return 0;
}

上面代码的输出为:

Command executed: New state
Restoring to state: New state
Command undone: New state

在这个示例中:

  • Command 是一个抽象类,定义了命令的接口,包括 execute 和 undo 方法。
  • ConcreteCommand 是 Command 的具体实现,它持有一个指向 Receiver 的 shared_ptr,并在 execute 方法中执行操作,同时保存当前状态以便在 undo 方法中恢复。
  • Receiver 类包含实际执行操作的逻辑,以及一个 restore 方法用于恢复之前的状态。
  • UndoManager 类负责管理命令的撤销操作,它使用一个 stack 来存储执行过的命令对象。当调用 executeCommand 方法时,它会执行命令并将其推入栈中;当调用 undoLastCommand 方法时,它会从栈顶弹出命令并执行其 undo 方法。

在 main 函数中,创建了一个 Receiver 对象和一个 ConcreteCommand 对象,并通过 UndoManager 来执行和撤销命令。通过使用 shared_ptr,可以确保 Receiver 和 ConcreteCommand 对象的生命周期得到妥善管理,即使在命令被撤销后也不会导致内存泄漏。

3.2 命令模式应用需要设计一组命令,并且命令之间可以相互组合的场景

在C++中,命令模式可以用于设计一组命令,并允许这些命令之间可以相互组合,形成复合命令。当需要执行一系列操作作为一个单一命令时,这种模式特别有用。如下为样例代码:

#include <iostream>  
#include <memory>  
#include <vector>  

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

// 具体命令类A  
class CommandA : public Command {
public:
	void execute() override {
		std::cout << "Executing CommandA" << std::endl;
	}
};

// 具体命令类B  
class CommandB : public Command {
public:
	void execute() override {
		std::cout << "Executing CommandB" << std::endl;
	}
};

// 复合命令类  
class CompositeCommand : public Command {
public:
	void addCommand(std::shared_ptr<Command> cmd) {
		commands.push_back(cmd);
	}

	void execute() override {
		for (const auto& cmd : commands) {
			cmd->execute();
		}
	}

private:
	std::vector<std::shared_ptr<Command>> commands;
};

int main() 
{
	// 创建具体命令对象  
	auto cmdA = std::make_shared<CommandA>();
	auto cmdB = std::make_shared<CommandB>();

	// 创建复合命令对象  
	auto compositeCmd = std::make_shared<CompositeCommand>();

	// 将具体命令添加到复合命令中  
	compositeCmd->addCommand(cmdA);
	compositeCmd->addCommand(cmdB);

	// 执行复合命令  
	compositeCmd->execute();

	return 0;
}

上面代码的输出为:

Executing CommandA
Executing CommandB

在这个示例中:

  • Command 是一个抽象基类,定义了命令的接口,即 execute 方法。
  • CommandA 和 CommandB 是具体命令类,分别实现了 execute 方法以执行特定的操作。
  • CompositeCommand 是一个复合命令类,它包含一个命令对象的 vector 容器。通过 addCommand 方法,可以将多个具体命令或复合命令添加到复合命令中。当调用 execute 方法时,它会依次执行容器中的每个命令。

在 main 函数中,创建了两个具体命令对象 cmdA 和 cmdB,然后创建了一个复合命令对象 compositeCmd。接着,将 cmdA 和 cmdB 添加到 compositeCmd 中。最后,调用 compositeCmd 的 execute 方法来执行复合命令,这将依次执行 cmdA 和 cmdB。

4 命令模式的优点与缺点

C++ 命令模式的优点主要包括:

(1)封装性: 每个命令都被封装起来,客户端无需知道命令具体是怎么执行的,只需调用相应的命令。这使得命令模式能够很好地隐藏实现细节,使系统更加模块化和可维护。

(2)扩展性: 命令模式符合开闭原则,即对扩展开放,对修改关闭。这意味着可以轻松地添加新命令而无需修改现有代码。

(3)支持撤销和重做: 命令模式可以方便地实现对请求的撤销和重做,这对于需要支持撤销操作的系统来说非常有用。

(4)请求排队和记录: 命令模式可以较容易地设计一个命令队列,以及在需要的情况下将命令记入日志。

(5)解耦: 命令模式将请求一个操作的对象与知道如何执行一个操作的对象分隔开,降低了系统的耦合度。

然而,C++ 命令模式也存在一些缺点:

(1)可能产生过多的具体命令类: 对于每一个命令,都需要设计一个具体命令类,这可能导致系统中存在大量的具体命令类,增加了系统的复杂性。

(2)可能导致过度设计: 在一些简单的场景下,使用命令模式可能过于复杂,导致过度设计,增加不必要的开销。文章来源地址https://www.toymoban.com/news/detail-840882.html

到了这里,关于突破编程_C++_设计模式(命令模式)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 设计模式-命令模式

    接受者(Receiver) 请求的实际作用对象 抽象命令(Command) 声明了执行请求的execute方法 具体命令(ConcreteCommand) 调用实际操作对象,实现execute 调用者(Invoker) 调用命令请求发送者 功能键绑定 比如遥控器的功能键,现在想要实现为功能可以自定义绑定事件,请使用命令模

    2024年02月09日
    浏览(40)
  • 设计模式之命令模式

    定义: 命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。 目的: 将一个请求封装成一个对象,从而使您

    2024年02月20日
    浏览(43)
  • 设计模式(19)命令模式

    一、介绍: 1、定义:命令模式(Command Pattern)是一种行为设计模式,它将请求封装为一个对象,从而使你可以使用不同的请求对客户端进行参数化。命令模式还支持请求的排队、记录日志、撤销操作等功能。 2、组成结构: (1)命令接口(Command):定义执行命令的方法,可

    2024年02月07日
    浏览(37)
  • 设计模式—行为型模式之命令模式

    命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行储存、传递、调用、增加与管理。 命令模式包含以下主要角色。 抽象命令类(Command)角色:声明执行命令的接口,

    2024年01月25日
    浏览(40)
  • 设计模式之命令模式【行为型模式】

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博

    2024年02月01日
    浏览(41)
  • 【设计模式--行为型--命令模式】

    定义 将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通,这样方便将命令对象进行存储,传递,调用,增加与管理。 结构 抽象命令类(Command)角色:定义命令的接口,声明执行的方法。 具体命令(Concrete Command)

    2024年02月04日
    浏览(37)
  • 设计模式行为型——命令模式

    目录 命令模式的定义      命令模式的实现 命令模式角色 命令模式类图 命令模式举例 命令模式代码实现 命令模式的特点 优点 缺点 使用场景 注意事项         命令模式(Command Pattern)是一种数据驱动的设计模式,它属于行为型模式。是对命令的封装,每一个命令都是

    2024年02月14日
    浏览(43)
  • 设计模式-命令模式(Command)

    命令模式(Command Pattern)是一种行为型设计模式,也被称为动作模式或事务模式。它的核心思想是将一个请求封装成一个对象,从而使你可以用不同的请求对客户进行参数化。对请求排队或记录,以及支持可撤销的操作。命令模式的主要目的是将发出请求的对象和执行请求的

    2024年04月27日
    浏览(34)
  • 设计模式之命令模式(下)

    2)完整解决方案 1.结构图 FBSettingWindow是“功能键设置”界面类,FunctionButton充当请求调用者,Command充当抽象命令类,MinimizeCommand和HelpCommand充当具体命令类,WindowHanlder和HelpHandler充当请求接收者。 2.代码实现 注意 : 每一个具体命令类对应一个请求的处理者(接收者),通过

    2024年04月10日
    浏览(61)
  • 【软考】设计模式之命令模式

    1. 说明 1.命令模式(Command Pattern)是一种数据驱动的设计模式。 2.属于行为型模式。 3.请求以命令的形式被封装在对象中,并传递给调用对象。 4.调用对象寻找可以处理该命令的合适对象,并将该命令传递给相应的对象,由该对象执行命令。 5.将请求(行为)封装为对象,从

    2024年04月16日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包