互動(dòng)網(wǎng)站案例培訓(xùn)教育機(jī)構(gòu)
命令模式 (Command)
命令模式 是一種行為型設(shè)計(jì)模式,它將請(qǐng)求封裝為一個(gè)對(duì)象,從而使得可以用不同的請(qǐng)求對(duì)客戶端進(jìn)行參數(shù)化、對(duì)請(qǐng)求排隊(duì)或記錄日志,以及支持可撤銷的操作。
意圖
- 將操作的調(diào)用者與接收者分離,通過將請(qǐng)求封裝為獨(dú)立對(duì)象,使得請(qǐng)求更加靈活。
- 支持撤銷、重做、記錄日志等操作。
使用場(chǎng)景
- 需要參數(shù)化請(qǐng)求:
- 客戶端不直接調(diào)用操作,而是通過封裝的命令對(duì)象。
- 需要支持撤銷 (Undo) 或重做 (Redo):
- 操作需要記錄歷史,以支持回滾或重試。
- 請(qǐng)求需要隊(duì)列化:
- 系統(tǒng)需要對(duì)請(qǐng)求排隊(duì)處理或記錄日志。
參與者角色
- 命令接口 (Command)
- 定義所有命令的公共接口。
- 具體命令類 (ConcreteCommand)
- 實(shí)現(xiàn)命令接口,調(diào)用接收者執(zhí)行具體操作。
- 接收者 (Receiver)
- 負(fù)責(zé)執(zhí)行具體操作的對(duì)象。
- 調(diào)用者 (Invoker)
- 負(fù)責(zé)調(diào)用命令。
- 客戶端 (Client)
- 創(chuàng)建命令對(duì)象,并將其傳遞給調(diào)用者。
示例代碼
以下代碼展示了命令模式的實(shí)現(xiàn),模擬智能家居系統(tǒng)控制燈光的打開、關(guān)閉操作,并支持撤銷功能。
#include <iostream>
#include <memory>
#include <stack>
#include <string>// 命令接口:定義命令的公共接口
class Command {
public:virtual ~Command() = default;// 執(zhí)行命令virtual void execute() = 0;// 撤銷命令virtual void undo() = 0;
};// 接收者:燈
class Light {
private:std::string name; // 燈的名稱public:explicit Light(std::string name) : name(std::move(name)) {}void turnOn() {std::cout << name << " 燈已打開。
";}void turnOff() {std::cout << name << " 燈已關(guān)閉。
";}
};// 具體命令類:打開燈的命令
class LightOnCommand : public Command {
private:Light& light; // 具體接收者:燈public:explicit LightOnCommand(Light& light) : light(light) {}void execute() override {light.turnOn(); // 打開燈}void undo() override {light.turnOff(); // 撤銷,關(guān)閉燈}
};// 具體命令類:關(guān)閉燈的命令
class LightOffCommand : public Command {
private:Light& light; // 具體接收者:燈public:explicit LightOffCommand(Light& light) : light(light) {}void execute() override {light.turnOff(); // 關(guān)閉燈}void undo() override {light.turnOn(); // 撤銷,打開燈}
};// 調(diào)用者:遙控器
class RemoteControl {
private:std::stack<std::unique_ptr<Command>> commandHistory; // 存儲(chǔ)命令歷史public:void executeCommand(std::unique_ptr<Command> command) {command->execute(); // 執(zhí)行命令commandHistory.push(std::move(command)); // 將命令存入歷史}void undoLastCommand() {if (!commandHistory.empty()) {auto& lastCommand = commandHistory.top(); // 獲取最近的命令lastCommand->undo(); // 撤銷命令commandHistory.pop(); // 移除該命令} else {std::cout << "無可撤銷的命令。
";}}
};// 客戶端代碼
int main() {Light livingRoomLight("客廳");Light bedroomLight("臥室");RemoteControl remoteControl;// 打開客廳燈remoteControl.executeCommand(std::make_unique<LightOnCommand>(livingRoomLight));// 關(guān)閉客廳燈remoteControl.executeCommand(std::make_unique<LightOffCommand>(livingRoomLight));// 打開臥室燈remoteControl.executeCommand(std::make_unique<LightOnCommand>(bedroomLight));// 撤銷最近一次操作remoteControl.undoLastCommand();// 撤銷最近一次操作remoteControl.undoLastCommand();return 0;
}
代碼解析
1. 命令接口 (Command)
- 定義了命令的公共接口,所有具體命令都需要實(shí)現(xiàn)
execute
和undo
方法。
class Command {
public:virtual ~Command() = default;virtual void execute() = 0;virtual void undo() = 0;
};
2. 接收者 (Light)
- 實(shí)現(xiàn)燈的具體操作,包括
turnOn
(打開燈)和turnOff
(關(guān)閉燈)。 - 是命令的實(shí)際執(zhí)行者。
class Light {
private:std::string name;
public:explicit Light(std::string name) : name(std::move(name)) {}void turnOn() { std::cout << name << " 燈已打開。
"; }void turnOff() { std::cout << name << " 燈已關(guān)閉。
"; }
};
3. 具體命令類
LightOnCommand
:- 在
execute
方法中調(diào)用turnOn
打開燈,在undo
方法中調(diào)用turnOff
撤銷。
- 在
LightOffCommand
:- 在
execute
方法中調(diào)用turnOff
關(guān)閉燈,在undo
方法中調(diào)用turnOn
撤銷。
- 在
class LightOnCommand : public Command {
private:Light& light;
public:explicit LightOnCommand(Light& light) : light(light) {}void execute() override { light.turnOn(); }void undo() override { light.turnOff(); }
};
4. 調(diào)用者 (RemoteControl)
RemoteControl
負(fù)責(zé)調(diào)用命令對(duì)象的execute
方法。- 使用棧 (
std::stack
) 存儲(chǔ)命令歷史,以支持撤銷。
class RemoteControl {
private:std::stack<std::unique_ptr<Command>> commandHistory;
public:void executeCommand(std::unique_ptr<Command> command) {command->execute();commandHistory.push(std::move(command));}void undoLastCommand() {if (!commandHistory.empty()) {commandHistory.top()->undo();commandHistory.pop();} else {std::cout << "無可撤銷的命令。
";}}
};
5. 客戶端
- 客戶端創(chuàng)建具體命令對(duì)象,并通過調(diào)用者
RemoteControl
執(zhí)行命令。 - 通過
undoLastCommand
撤銷命令。
優(yōu)缺點(diǎn)
優(yōu)點(diǎn)
- 解耦調(diào)用者與接收者:
- 調(diào)用者無需知道接收者的具體實(shí)現(xiàn)。
- 支持撤銷和重做:
- 通過記錄命令歷史,支持操作的撤銷和重做。
- 命令隊(duì)列化:
- 可以輕松實(shí)現(xiàn)請(qǐng)求的排隊(duì)處理。
缺點(diǎn)
- 類數(shù)量增加:
- 每個(gè)操作都需要定義一個(gè)具體命令類。
- 存儲(chǔ)開銷:
- 需要存儲(chǔ)命令歷史以支持撤銷和重做。
適用場(chǎng)景
- 參數(shù)化請(qǐng)求:
- 將請(qǐng)求封裝為獨(dú)立對(duì)象,客戶端無需直接調(diào)用。
- 操作的撤銷和重做:
- 系統(tǒng)需要支持操作回滾。
- 請(qǐng)求隊(duì)列化:
- 系統(tǒng)需要對(duì)請(qǐng)求進(jìn)行排隊(duì)或記錄日志。
總結(jié)
命令模式通過將請(qǐng)求封裝為對(duì)象,實(shí)現(xiàn)了請(qǐng)求的參數(shù)化、撤銷、排隊(duì)處理等功能,是一種優(yōu)雅的行為模式。適用于需要解耦調(diào)用者和接收者的場(chǎng)景,尤其在支持撤銷或重做的系統(tǒng)中表現(xiàn)出色。