C++实现Behavioral - Command模式

【转载】 C++实现Behavioral - Command模式

转载自:http://patmusing.blog.163.com/blog/static/13583496020101501317634/

The COR (Chain Of Responsibility) pattern forwards requests along a chain of classes, but the Command pattern forwards a request only to a specific object. It encloses the request for a specific action inside an object and gives it a known public interface.
It lets you give the client the ability to make requests without knowing anything about the actual action that will be performed and allows you to change that action without affecting the client program in any way.

One way to ensure that every object receives its own commands directly is to use the Command design pattern and create individual Command objects.

在软件构建过程中,行为请求者行为实现者通常呈现一种紧耦合。但在某些场合,比如需要对行为进行记录、撤销/重做(undo/redo)、事务等处理,这种无法抵御变化的紧耦合是不合适的。Command设计模式就是在这种情况下,将行为请求者行为实现者解耦,将一组行为抽象为对象,以实现二者之间的松耦合。

“Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.” – GoF

将一个请求封装为一个对象,从而可用不同的请求(一个被封装成了对象的请求)对客户程序(即调用者)进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

Command存在的两个重要原因:

1. 解耦

 C++实现Behavioral - Command模式_第1张图片

2. 由于C#Java不存在指针,因此不能将请求(即方法或者成员函数)作为参数进行传递或者存储。在C++中尽管可以使用函数指针达到同样的效果,但使用Command模式还是可以是代码更容易理解一些。

最基本的Command模式之UML类图:

 C++实现Behavioral - Command模式_第2张图片

C++具体实现代码:

// Command.h

#include <iostream>

#include <string>

#include <memory>

using namespace std;

// 抽象类

class Command

{

public:

virtual void execute() = 0;

public:

virtual ~Command()

{

cout << "in the destructor of Command..." << endl;

}

};

// Receiver

class Document

{

public:

void doDocument()

{

cout << "this is in Document::doDocument()..." << endl;

}

public:

~Document()

{

cout << "in the destructor of Document..." << endl;

}

};

// Receiver

class Graphics

{

public:

void doGraphics()

{

cout << "this is in Graphics::doGraphics()..." << endl;

}

public:

~Graphics()

{

cout << "in the destructor of Graphics..." << endl;

}

};

// ConcreteCommand

class DocumentCommand : public Command

{

private:

auto_ptr<Document> document;

public:

DocumentCommand()

{

auto_ptr<Document> temp_document(new Document);

document = temp_document;

}

~DocumentCommand()

{

cout << "in the destructor of DocumentCommand..." << endl;

}

public:

void execute()

{

cout << "this is in DocumentCommand::execute()..." << endl;

document->doDocument();

}

};

// ConcreteCommand

class GraphicsCommand : public Command

{

private:

auto_ptr<Graphics> graphics;

public:

GraphicsCommand()

{

auto_ptr<Graphics> temp_graphics(new Graphics);

graphics = temp_graphics;

}

~GraphicsCommand()

{

cout << "in the destructor of GraphicsCommand..." << endl;

}

public:

void execute()

{

cout << "this is in GraphicsCommand::execute()..." << endl;

graphics->doGraphics();

}

};

// Command.cpp

#include "Command.h"

int main(int argc, char **argv)

{

auto_ptr<Command> cmd1(new DocumentCommand);

auto_ptr<Command> cmd2(new GraphicsCommand);

cmd1->execute();

cout << "-------------------------------------" << endl;

cmd2->execute();

cout << "-------------------------------------" << endl;

return 0;

}

输出结果:

this is in DocumentCommand::execute()...

this is in Document::doDocument()...

-------------------------------------

this is in GraphicsCommand::execute()...

this is in Graphics::doGraphics()...

-------------------------------------

in the destructor of GraphicsCommand...

in the destructor of Graphics…

in the destructor of Command...

in the destructor of DocumentCommand...

in the destructor of Document...

in the destructor of Command...

说明:上面的实现的Command模式从形式来说和对象类型的Adapter几乎没有区别。

Command模式的变体(实现undo/redo)

 C++实现Behavioral - Command模式_第3张图片

注意:这个类图是下面将要用C++代码实现的示例程序中各类之间的关系图。该示例程序用Command模式模拟了一个文本编辑器的undo/redo。下面是该示例程序的全部代码:

// Command.h

#include <iostream>

#include <string>

#include <stack>

using namespace std;

class Receiver

{

private:

string str;

public:

~Receiver()

{

cout << "in the destructor of Receiver..." << endl;

}

public:

void append(const string& str)

{

this->str += str;

}

void set_data(const string& str)

{

this->str = str;

}

string get_data()

{

return str;

}

};

class Command

{

protected:

Receiver *receiver;

string parameter;

public:

Command(Receiver *receiver, string parameter) : receiver(receiver), parameter(parameter)

{

}

virtual ~Command()

{

cout << "in the destructor of Command..." << endl;

}

public:

virtual void execute() = 0;

};

class UndoableCommand : public Command

{

public:

UndoableCommand(Receiver *receiver, string parameter) : Command(receiver, parameter)

{

// 将接收到的参数,传递给基类构造函数

}

virtual ~UndoableCommand()

{

cout << "in the destructor of UndoableCommand..." << endl;

}

public:

virtual void undo() = 0;

virtual void redo() = 0;

};

class ConcreteCommand : public UndoableCommand

{

private:

string previous_str;

string current_str;

public:

ConcreteCommand(Receiver *receiver, string parameter) : UndoableCommand(receiver, parameter)

{

// 将接收到的参数传递给基类

}

~ConcreteCommand()

{

cout << "in the destructor of ConcreteCommand..." << endl;

}

public:

void execute()

{

previous_str = receiver->get_data();

receiver->append(parameter);

current_str = receiver->get_data();

}

void undo()

{

receiver->set_data(previous_str);

}

void redo()

{

receiver->set_data(current_str);

}

};

class CommandManager

{

private:

// executeCommandStack用来存放已经执行过的名利了呢个,以便undo

stack<Command*> executeCommandStack;

// undoCommandStack用来存放undo过的命令,以便redo

stack<Command*> undoCommandStack;

public:

~CommandManager()

{

cout << "in the destructor of CommandManager..." << endl;

}

public:

void executeCommand(Command *command)

{

command->execute();

// 保存操作结果。将执行过的Command,压入executeCommandStack

executeCommandStack.push(command);

}

void undoCommand()

{

if(executeCommandStack.size() > 0)

{

// executeCommandStack弹出最后一次执行的command

UndoableCommand *command = dynamic_cast<UndoableCommand*>(executeCommandStack.top());

executeCommandStack.pop();

command->undo();

// command压入undoCommandStack

undoCommandStack.push(command);

}

}

void redoCommand()

{

if(undoCommandStack.size() > 0)

{

// undoCommandStack弹出最后一次执行的command

UndoableCommand *command = dynamic_cast<UndoableCommand*>(undoCommandStack.top());

undoCommandStack.pop();

command->redo();

}

}

};

// Command.cpp

#include "Command.h"

int main(int argc, char **argv)

{

CommandManager *commandMan = new CommandManager;

Receiver *receiver = new Receiver;

cout << "---execute command---" << endl;

Command *command_A = new ConcreteCommand(receiver, "aaa\n");

commandMan->executeCommand(command_A);

Command *command_B = new ConcreteCommand(receiver, "bbb\n");

commandMan->executeCommand(command_B);

Command *command_C = new ConcreteCommand(receiver, "ccc\n");

commandMan->executeCommand(command_C);

Command *command_D = new ConcreteCommand(receiver, "ddd\n");

commandMan->executeCommand(command_D);

cout << "the data in receiver:" << endl;

cout << receiver->get_data() << endl;

cout << "---undo---: After undo twice..." << endl;

commandMan->undoCommand();

commandMan->undoCommand();

cout << "the data in receiver:" << endl;

cout << receiver->get_data() << endl;

cout << "---redo---: After redo twice..." << endl;

commandMan->redoCommand();

commandMan->redoCommand();

cout << "the data in receiver:" << endl;

cout << receiver->get_data() << endl;

delete commandMan;

delete receiver;

delete command_A;

delete command_B;

delete command_C;

delete command_D;

return 0;

}

运行结果:

---execute command---

the data in receiver:

aaa

bbb

ccc

ddd

---undo---: After undo twice...

the data in receiver:

aaa

bbb

---redo---: After redo twice...

the data in receiver:

aaa

bbb

ccc

ddd

in the destructor of CommandManager...

in the destructor of Receiver...

in the destructor of ConcreteCommand...

in the destructor of UndoableCommand...

in the destructor of Command...

in the destructor of ConcreteCommand...

in the destructor of UndoableCommand...

in the destructor of Command...

in the destructor of ConcreteCommand...

in the destructor of UndoableCommand...

in the destructor of Command...

in the destructor of ConcreteCommand...

in the destructor of UndoableCommand...

in the destructor of Command...

在上面的程序中,我们看到了Command对象作为参数进行传递(因为在JavaC#中,由于不存在指针,因此方法本身不能作为参数进行传递,在C++尽管有指针,如果使用Command设计模式,还是可以提高解耦的能力,同时可以使代码更具有可读性),除去解耦的宗旨外,Command设计模式最重要的实质就是,就是将方法封装成为对象,从而可以作为参数进行传递。

C++中,一定程度上,也可以将Command对象理解成函数对象(function objectfunctor,有人称之为仿函数,玄机逸士认为成为函数对象更合适一些),关于函数对象参见:函数对象

还有一点,上面的Receiver类,可以考虑用Singleton模式来实现。

Command对象的本质就是在该对象中指定了需要执行某种操作的接受者。

你可能感兴趣的:( C++实现Behavioral - Command模式)