Design pattern: Command pattern C + + implementation

preface

Today I reviewed the command mode, which is very interesting. Here I share it with you!

1. Command mode understanding

Command mode is to separate the command issuer from the command executor so that they are not directly connected, but record these commands through a third party, and then the third party tells the command executor to execute them. In the middle, commands can be added or deleted on the basis of previous commands, realizing loose coupling.

"Dahua design pattern" gives a very appropriate example: people who buy kebabs and people who bake kebabs. People who buy kebabs at roadside stalls directly tell the kebabs what they want. If there are many people, it is easy to make mistakes. With the command mode, it is equivalent to that the roaster has a shop, a waiter and a menu. The person who buys the roaster directly communicates with the waiter. The waiter records the customer's requirements on the menu, and then the waiter passes the menu to the roaster through the kitchen. In this way, the roaster can bake the roaster according to this menu, and there is no need to worry about making mistakes, It is not only convenient to calculate bills, but also convenient for customers to refund bills, etc.

The more formal definition and class diagram of command mode (referring to Dahua design mode) are as follows:


In the above class diagram, the Client is equivalent to the person who buys the kebab, the Invoker is equivalent to the waiter, the Command is equivalent to the menu, the strings ordered by the customer are recorded, and the Receiver is equivalent to the person who makes the kebab. Is it very clear!

2. Command mode C + + implementation

Here, the command mode is realized by taking eating roasted string in the store as an example. The class diagram (quoting Dahua design mode) is as follows:

The implementation of C + + code is as follows:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>
#include <memory>
#include <list>
#include <chrono>

// Get the current system time
std::string getCurrentSystemTime()
{
	auto tt = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
	struct tm* ptm = localtime(&tt);
	char date[60] = { 0 };
	sprintf(date, "%d-%02d-%02d-%02d.%02d.%02d",
		(int)ptm->tm_year + 1900, (int)ptm->tm_mon + 1, (int)ptm->tm_mday,
		(int)ptm->tm_hour, (int)ptm->tm_min, (int)ptm->tm_sec);
	return std::string(date);
}

//**************************Command Pattern*********************
//Kebab
class Barbecuer
{
public:
	void BakeMutton()
	{
		std::cout << "shish kebab!" << std::endl;
	}

	void BakeChickenWing()
	{
		std::cout << "Roast chicken wings!" << std::endl;
	}
};

//Abstract command class
class Command
{
protected:
	std::shared_ptr<Barbecuer> smartBarbecuer;
	std::string strDescription;
public:
	Command(std::shared_ptr<Barbecuer> pBarbecuer, const std::string& strDesc): smartBarbecuer(pBarbecuer), strDescription(strDesc) {}

	virtual void ExecuteCommand() = 0;

	std::string GetDescription() const
	{
		return strDescription;
	}
};

//Kebab command
class BakeMuttonCommand : public Command
{
public:
	BakeMuttonCommand(std::shared_ptr<Barbecuer> receiver, const std::string& strDesc = "shish kebab"): Command(receiver, strDesc){}

	void ExecuteCommand()
	{
		smartBarbecuer->BakeMutton();
	}
};

//Roast chicken wing string command
class BakeChickenWingCommand : public Command
{
public:
	BakeChickenWingCommand(std::shared_ptr<Barbecuer> receiver, const std::string& strDesc = "Roast chicken wing string") : Command(receiver, strDesc) {}

	void ExecuteCommand()
	{
		smartBarbecuer->BakeChickenWing();
	}
};

//Waiter class
class Waiter
{
private:
	std::list<std::shared_ptr<Command>> orders;

public:
	void SetOrder(std::shared_ptr<Command> command)
	{
		if (command->GetDescription() == "Roast chicken wing string")
		{
			std::cout << "Waiter: there are no chicken wings. Please order something else!" << std::endl;
		}
		else
		{
			orders.push_back(command);
			std::cout << "Add order:" << command->GetDescription().c_str() << ", Time:" << getCurrentSystemTime().c_str() << std::endl;
		}
	}

	void CancelOrder(std::shared_ptr<Command> command)
	{
		orders.remove(command);
		std::cout << "cancellation of order:" << command->GetDescription().c_str() << ", time: " << getCurrentSystemTime().c_str() << std::endl;
	}

	void Notify()
	{
		std::cout << "Here comes the order. The kitchen can start baking kebabs!" << std::endl;
		for (std::shared_ptr<Command> command : orders)
		{
			command->ExecuteCommand();
		}
	}
};

//****************************Test******************************
int main()
{
	//Preparation before opening the store
	std::shared_ptr<Barbecuer> boy = std::make_shared<Barbecuer>();
	std::shared_ptr<Command> bakeMuttonC1 = std::make_shared<BakeMuttonCommand>(boy);
	std::shared_ptr<Command> bakeMuttonC2 = std::make_shared<BakeMuttonCommand>(boy);
	std::shared_ptr<Command> bakeChickenWingC1 = std::make_shared<BakeChickenWingCommand>(boy);
	std::shared_ptr<Waiter> waiter = std::make_shared<Waiter>();

	//Open, customers order
	waiter->SetOrder(bakeMuttonC1);
	waiter->SetOrder(bakeMuttonC2);
	waiter->SetOrder(bakeChickenWingC1);

	//After ordering, inform the kitchen
	waiter->Notify();

	//Customer cancels order
	waiter->CancelOrder(bakeMuttonC1);

	//After ordering, inform the kitchen
	waiter->Notify();

	system("pause");
	return 0;
}

summary

Command mode realizes the separation of requester and implementer, realizes loose coupling and improves scalability.
Personal feeling, command pattern is the result of the application output of the combination of relationship and thing abstraction ability. The abstract ability of things is very important. If the abstract ability is used well, the application of design patterns is not difficult!

reference resources

Dahua design mode

Keywords: C++ Design Pattern

Added by Design on Fri, 17 Dec 2021 20:16:03 +0200