Реализация паттерна Command

Рассмотрим реализацию паттерна Command на примере игры «Шахматы». Имитируем возможность выполнения следующих операций:

· Создать новую игру.

· Открыть существующую игру.

· Сохранить игру.

· Сделать очередной ход.

· Отменить последний ход.

#include<iostream> #include<vector> #include<string> class Game { public: void create() { cout << "Create game " << endl; } void open(string file) { cout << "Open game from " << file << endl; } void save(string file) { cout << "Save game in " << file << endl; } void make_move(string move) { cout << "Make move " << move << endl; } }; string getPlayerInput(string prompt) { string input; cout << prompt; cin >> input; return input; } // Базовый класс class Command { public: virtual ~Command() {} virtual void execute() = 0; protected: Command(Game* p): pgame(p) {} Game * pgame; }; class CreateGameCommand: public Command { public: CreateGameCommand(Game * p): Command(p) {} void execute() { pgame->create(); } }; class OpenGameCommand: public Command { public: OpenGameCommand(Game * p): Command(p) {} void execute() { string file_name; file_name = getPlayerInput("Enter file name:"); pgame->open(file_name); } }; class SaveGameCommand: public Command { public: SaveGameCommand(Game * p): Command(p) {} void execute() { string file_name; file_name = getPlayerInput("Enter file name:"); pgame->save(file_name); } }; class MakeMoveCommand: public Command { public: MakeMoveCommand(Game * p): Command(p) {} void execute() { // Сохраним игру для возможного последующего отката pgame->save("TEMP_FILE"); string move; move = getPlayerInput("Enter your move:"); pgame->make_move(move); } }; class UndoCommand: public Command { public: UndoCommand(Game * p): Command(p) {} void execute() { // Восстановим игру из временного файла pgame->open("TEMP_FILE"); } }; int main() { Game game; // Имитация действий игрока vector<Command*> v; // Создаем новую игру v.push_back(new CreateGameCommand(&game)); // Делаем несколько ходов v.push_back(new MakeMoveCommand(&game)); v.push_back(new MakeMoveCommand(&game)); // Последний ход отменяем v.push_back(new UndoCommand(&game)); // Сохраняем игру v.push_back(new SaveGameCommand(&game)); for (size_t i=0; i<v.size(); ++i) v[i]->execute(); for (size_t i=0; i<v.size(); ++i) delete v[i]; return 0; }

Вывод программы:

Create game Save game in TEMP_FILE Enter your move: E2-E4 Make move E2-E4 Save game in TEMP_FILE Enter your move: D2-D3 Make move D2-D3 Open game from TEMP_FILE Enter file name: game1.sav Save game in game1.sav

Результаты применения паттерна Command

Достоинства паттерна Command

· Придает системе гибкость, отделяя инициатора запроса от его получателя.

    Пример:

#include <iostream>

#include <vector>

#include <string>

using namespace std;

Class Document

{

vector<string> data;

public:

void Insert(int line, const string & str)

{

if (line <= data.size())

    data.insert(data.begin() + line, str);

else

    cout << "Error!" << endl;

}

void Remove(int line)

{

if(!(line>data.size()))

    data.erase(data.begin() + line);

else

    cout << "Error!" << endl;

}

string & operator [] (int x)

{

return data[x];

}

void Show()

{

for(int i = 0; i<data.size(); ++i)

{

    cout << i + 1 << ". " << data[i] << endl;

}

}

};

Class Command

{

protected:

Document * doc;

public:

virtual void Execute() = 0;

virtual void unExecute() = 0;

void setDocument(Document * _doc)

{

doc = _doc;

}

};

Class InsertCommand: public Command

{

int line;

string str;

public:

InsertCommand(int _line, const string & _str): line(_line), str(_str) {}

void Execute()

{

doc->Insert(line, str);

}

void unExecute()

{

doc->Remove(line);

}

};

Class Receiver

{

vector<Command*> DoneCommands;

Document doc;

Command* command;

public:

void Insert(int line, string str)

{

command = new InsertCommand(line, str);

command->setDocument(&doc);

command->Execute();

DoneCommands.push_back(command);

}

void Undo()

{

if(DoneCommands.size() == 0)

{

    cout << "There is nothing to undo!" << endl;

}

else

{

    command = DoneCommands.back();

    DoneCommands.pop_back();

    command->unExecute();

    // Don't forget to delete command!!!

    delete command;

}

}

void Show()    

{

doc.Show();

}

};

Int main()

{

char s = '1';

int line, line_b;

string str;

Receiver res;

while(s!= 'e')

{

cout << "What to do: \n1.Add a line\n2.Undo last command" << endl;

cin >> s;

switch(s)

{

case '1':

    cout << "What line to insert: ";

    cin >> line;

    --line;

    cout << "What to insert: ";

    cin >> str;

    res.Insert(line, str);

    break;

case '2':

    res.Undo();

    break;

}

cout << "$$$DOCUMENT$$$" << endl;

res.Show();

cout << "$$$DOCUMENT$$$" << endl;

}

}

Задания для лабораторной работы

В каждом из вариантов указан шаблон для реализации и проект, использующий этот шаблон.

Необходимо сделать следующее:

1. Нарисовать в UML диаграмму классов реализуемой программы. (проектирование)

2. Реализовать программу на С++. (реализация)

 

Для каждого из шаблонов, предложенных в вариантах можно найти пример реализации UML и кода в приложенной книге “Паттерны проектирования”.

Также указана глава, где подробно описан данный шаблон.

Вариант №1, 9, 17, 25

Шаблон “Стратегия”. Проект “Принтеры”. В проекте должны быть реализованы разные модели принтеров, которые выполняют разные виды печати. Пример использования шаблона в главе 1.

Вариант №2, 10, 18, 26

Шаблон “Наблюдатель”. Проект “Оповещение постов ГАИ”. В проекте должна быть реализована отправка сообщений всем постам ГАИ. Пример использования шаблона в главе 2.

Вариант №3, 11, 19, 27

Шаблон “Декоратор”. Проект “Универсальная электронная карта”. В проекте должна быть реализована универсальная электронная карта, в которой есть функции паспорта, страхового полиса, банковской карты и т. д. Пример использования шаблона в главе 3.

Вариант №4, 12, 20, 28

Шаблон “Фабричный метод”. Проект “Фабрика смартфонов”. В проекте должно быть реализовано создание смартфонов с различными характеристиками. Пример использования шаблона в главе 4.

Вариант №5, 13, 21, 29

Шаблон “Абстрактная фабрика”. Проект “Заводы по производству автомобилей”. В проекте должно быть реализована возможность создавать автомобили различных типов на разных заводах.

Вариант №6, 14, 22, 30

Шаблон “Команда”. Проект “Клавиатура настраимаемого калькулятора”. Цифровые и арифметические кнопки имеют фиксированную функцию, а остальные могут менять своё назначение.

Вариант №7, 15, 23

Шаблон “Адаптер”. Проект “Часы”. В проекте должен быть реализован адаптер, который дает возможность пользоваться часами со стрелками так же, как и цифровыми часами. В классе “Часы со стрелками” хранятся повороты стрелок. Пример использования шаблона в главе 7.

Вариант №8, 16, 24

Шаблон “Фасад”. Проект “Компьютер”. В проекте должен быть реализован “компьютер”, который выполняет основные функции, к примеру, включение, выключение, запуск ОС, запуск программы, и т.д, не раскрывая клиенту деталей выполнения этой операции. Пример использования шаблона в главе 7.

 

 

Литература, ссылки

1. https://ru.wikipedia.org/wiki/%D8%E0%E1%EB%EE%ED_%EF%F0%EE%E5%EA%F2%E8%F0%

EE%E2%E0%ED%E8%FF

2. http://citforum.ru/SE/project/pattern/

3. Э.Фримен, К.Сьерра, Б.Бейтс Паттерны проектирования. СПб.:

Питер, 2011.

4. Классическая книга “банды четырех”. Э. Гамма, Р. Хелм, Р. Джонсон, Д. Влиссидес. Приемы объектно-ориентированного

проектирования. Паттерны проектирования. (разные издания,

последнее 2015).

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: