介紹
? ? ? ? 命令模式將一個請求封裝為一個對象,從而可用不同的請求對客戶進行參數化;對請求排隊或者記錄請求日志,以及支持可撤銷的操作。命令模式是一種對象行為模式,其別名為動作模式或事務模式。
實現(xiàn)
myclass.h
//
// Created by yuwp on 2024/1/12.
//
#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H
#include <iostream>
#include <unordered_map>
#include <atomic>
class Command { // 命令抽象類
public:
virtual void execute() = 0;
};
class Reciever { // 命令接收者,可以繼承實現(xiàn)具體的接收類
public:
virtual void action();
};
class ConcreteCommand : public Command { // 具體命令類
public:
ConcreteCommand();
~ConcreteCommand();
void execute() override;
private:
Reciever *m_reciever;
};
class Invoker { // 調用者類,命令發(fā)送者
public:
Invoker(Command *command);
void call();
private:
Command *m_command;
};
#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//
#include "myclass.h"
#include <thread>
#include <unistd.h>
ConcreteCommand::ConcreteCommand() {
m_reciever = new Reciever();
}
ConcreteCommand::~ConcreteCommand() {
if (m_reciever)
delete m_reciever;
}
void ConcreteCommand::execute() {
m_reciever->action();
}
void Reciever::action() {
std::cout << "接收者處理命令" << std::endl;
}
Invoker::Invoker(Command *command) {
m_command = command;
}
void Invoker::call() {
m_command->execute();
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"
int main() {
Command *command = new ConcreteCommand();
Invoker *invoker = new Invoker(command);
invoker->call();
return 0;
}
命令隊列實現(xiàn)
? ? ? ? 只需要增加一個CommandQueue類即可,Invoker中保存對CommandQueue的引用。
myclass.h
//
// Created by yuwp on 2024/1/12.
//
#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H
#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
class Command { // 命令抽象類
public:
virtual void execute() = 0;
};
class Reciever { // 命令接收者,可以繼承實現(xiàn)具體的接收類
public:
virtual void action();
};
class ConcreteCommand : public Command { // 具體命令類
public:
ConcreteCommand();
~ConcreteCommand();
void execute() override;
private:
Reciever *m_reciever;
};
class CommandQueue {
public:
void execute();
void addCommand(Command *command);
void removeCommand(Command *command);
private:
std::vector<Command *> m_commands;
};
class Invoker { // 調用者類,命令發(fā)送者
public:
Invoker(CommandQueue *commands);
void call();
private:
CommandQueue *m_commands;
};
#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp
//
// Created by yuwp on 2024/1/12.
//
#include "myclass.h"
#include <thread>
#include <unistd.h>
ConcreteCommand::ConcreteCommand() {
m_reciever = new Reciever();
}
ConcreteCommand::~ConcreteCommand() {
if (m_reciever)
delete m_reciever;
}
void ConcreteCommand::execute() {
m_reciever->action();
}
void Reciever::action() {
std::cout << "接收者處理命令" << std::endl;
}
Invoker::Invoker(CommandQueue *commands) {
m_commands = commands;
}
void Invoker::call() {
m_commands->execute();
}
void CommandQueue::execute() {
for (auto it = m_commands.begin(); it != m_commands.end(); ++it) {
(*it)->execute();
}
}
void CommandQueue::addCommand(Command *command) {
m_commands.push_back(command);
}
void CommandQueue::removeCommand(Command *command) {
for (auto it = m_commands.begin(); it != m_commands.end(); ) {
if (*it == command) {
it = m_commands.erase(it);
} else {
++it;
}
}
}
main.cpp
#include <iostream>
#include <mutex>
#include "myclass.h"
int main() {
Command *command = new ConcreteCommand();
CommandQueue *queue = new CommandQueue();
queue->addCommand(command);
Invoker *invoker = new Invoker(queue);
invoker->call();
delete invoker;
delete queue;
delete command;
return 0;
}
撤銷操作
? ? ? ? 在命令類中增加一個逆向操作,也可以通過保存對象的歷史狀態(tài)來實現(xiàn)狀態(tài)回滾。
請求日志
? ? ? ? 執(zhí)行命令時增加日志的記錄操作。
宏命令
? ? ? ? 組合模式和命令模式的結合,可以實現(xiàn)批量命令的執(zhí)行,與命令隊列類似,不同的是宏命令類繼承自命令抽象類(Command),可以遞歸調用。
總結
優(yōu)點
? ? ? ? 1.?降低系統(tǒng)的耦合度。由于請求者與接收者之間不存在直接引用,因此請求者與接收者之間實現(xiàn)完全解耦,相同的請求者可以對應不同的接收者。同樣,相同的接收者也可以供不同的請求者使用,兩者之間具有良好的獨立性。
? ? ? ? 2.?新的命令可以很容易地加入系統(tǒng)中。由于增加新的具體命令類不會影響到其他類,因此增加新的具體命令類很容易,無須修改原有系統(tǒng)源代碼甚至客戶類代碼,滿足開閉原則的要求。
? ? ? ? 3.?可以比較容易地設計一個命令隊列或宏命令(組合命令)。
? ? ? ? 4.?為請求的撤銷(Undo)和恢復(Redo)操作提供了一種設計和實現(xiàn)方案。
缺點
? ? ? ? 1.?使用命令模式可能會導致某些系統(tǒng)有過多的具體命令類。因為針對每一個對請求接收者的調用操作都需要設計一個具體命令類,因此在某些系統(tǒng)中可能需要提供大量的具體命令類,這將影響命令模式的使用。
適用場景
? ? ? ? 1.?系統(tǒng)需要將請求調用者和請求接收者解耦,使得調用者和接收者不直接交互。請求調用者無須知道接收者的存在,也無須知道接收者是誰,接收者也無須關心何時被調用。
? ? ? ? 2.?系統(tǒng)需要在不同的時間指定請求、將請求排隊和執(zhí)行請求。一個命令對象和請求的初始調用者可以有不同的生命期。換言之,最初的請求發(fā)出者可能已經不在了,而命令對象本身仍然是活動的,可以通過該命令對象去調用請求接收者,而無須關心請求調用者的存在性,可以通過請求日志文件等機制來具體實現(xiàn)。
? ? ? ? 3.?系統(tǒng)需要支持命令的撤銷(Undo)操作和恢復(Redo)操作。
? ? ? ? 4.?系統(tǒng)需要將一組操作組合在一起形成宏命令。
練習
myclass.h
//
// Created by yuwp on 2024/1/12.
//
#ifndef DESIGNPATTERNS_MYCLASS_H
#define DESIGNPATTERNS_MYCLASS_H
#include <iostream>
#include <unordered_map>
#include <atomic>
#include <vector>
class Command { // 命令抽象類
public:
virtual void execute() = 0;
};
class BoardScreen { // 命令接收者
public:
void open();
void create();
void edit();
};
class OpenCommand : public Command { // 具體命令類
public:
OpenCommand(BoardScreen *reciever);
void execute() override;
private:
BoardScreen *m_reciever;
};
class CreateCommand : public Command { // 具體命令類
public:
CreateCommand(BoardScreen *reciever);
void execute() override;
private:
BoardScreen *m_reciever;
};
class EditCommand : public Command { // 具體命令類
public:
EditCommand(BoardScreen *reciever);
void execute() override;
private:
BoardScreen *m_reciever;
};
class Invoker { // 調用者類,命令發(fā)送者
public:
Invoker(Command *command);
void call();
private:
Command *m_command;
};
#endif //DESIGNPATTERNS_MYCLASS_H
myclass.cpp文章來源:http://www.zghlxwxcb.cn/news/detail-808172.html
//
// Created by yuwp on 2024/1/12.
//
#include "myclass.h"
#include <thread>
#include <unistd.h>
void BoardScreen::open() {
std::cout << "打開" << std::endl;
}
void BoardScreen::create() {
std::cout << "新建" << std::endl;
}
void BoardScreen::edit() {
std::cout << "編輯" << std::endl;
}
OpenCommand::OpenCommand(BoardScreen *reciever) {
m_reciever = reciever;
}
void OpenCommand::execute() {
m_reciever->open();
}
CreateCommand::CreateCommand(BoardScreen *reciever) {
m_reciever = reciever;
}
void CreateCommand::execute() {
m_reciever->create();
}
EditCommand::EditCommand(BoardScreen *reciever) {
m_reciever = reciever;
}
void EditCommand::execute() {
m_reciever->edit();
}
Invoker::Invoker(Command *command) {
m_command = command;
}
void Invoker::call() {
m_command->execute();
}
main.cpp文章來源地址http://www.zghlxwxcb.cn/news/detail-808172.html
#include <iostream>
#include <mutex>
#include "myclass.h"
int main() {
BoardScreen *boardScreen = new BoardScreen();
Command *command = new OpenCommand(boardScreen);
Invoker *invoker = new Invoker(command);
invoker->call();
delete command;
delete invoker;
command = new CreateCommand(boardScreen);
invoker = new Invoker(command);
invoker->call();
delete command;
delete invoker;
command = new EditCommand(boardScreen);
invoker = new Invoker(command);
invoker->call();
delete command;
delete invoker;
return 0;
}
到了這里,關于《設計模式的藝術》筆記 - 命令模式的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!