|
|||
Основные виды порождающих шаблоновОсновные виды порождающих шаблонов Абстрактная фабрика (AbstractFactory) Абстрактная фабрика — порождающий шаблон проектирования, позволяющий изменять поведение системы, варьируя создаваемые объекты, при этом сохраняя интерфейсы. Он позволяет создавать целые группы взаимосвязанных объектов, которые, будучи созданными одной фабрикой, реализуютобщее поведение. Шаблон реализуется созданием абстрактного класса Factory, который представляет собой интерфейс для создания компонентов системы. Затем разрабатываются классы, реализующие этот интерфейс. Этот шаблон предоставляет интерфейс для создания множества взаимосвязанных объектов, не специфицируя их конкретных классов.Фабрика имеет некую специализацию, создавая товары или устройства какого-либо определенного типа.Фабрика, которая выпускает, например, мебель, не может производить, например, еще и компоненты для смартфонов. В программировании фабрика объектов может создавать только объекты определенного типа, которые используют единый интерфейс.Самыми главными преимуществами данного паттерна в С++, является упрощение создания объектов различных классов, использующих единый интерфейс. Паттерн предоставляет интерфейс для создания семейств, связанных между собой, или независимых объектов, конкретные классы которых неизвестны.От класса «абстрактная фабрика» наследуются классы конкретных фабрик, которые содержат методы создания конкретных объектов-продуктов, являющихся наследниками класса «абстрактный продукт», объявляющего интерфейс для их создания. Пример реализации абстрактной фабрики на C++ Предположим, необходимо разработать игровую стратегию, в которой есть две противоборствующие стороны. Каждая сторона имеет свою армию. Каждая армия – своих воинов, характеристики которых могут отличаться. Может также отличаться и требуемое количество ресурсов, необходимое для создания того или иного воина. Для простоты будем считать, что у каждого воина есть количество жизней, параметр атаки (количество жизней, отнимаемое у соперника за один ход), количество единственного ресурса «еда», необходимое для производства воина. (Понятно, что в будущем можно будет расширять подобную стратегию – добавить новые ресурсы (например, дерево для производства лучников), добавлять показатели брони для защиты персонажей от атаки соперников и т.д., но в приводимом ниже коде это не используется).
Содержимое файла archer.h #ifndef _ARCHER_ #define _ARCHER_ 1
// Интерфейс, представляющий собой абстрактного лучника class Archer { protected: int totalLive; // Количествожизнейуперсонажа int attackLive; // Количество жизней, снимаемых при атаке int resourceCount; // Количество ресурсов, необходимое для производства лучника public: virtualint getLive() = 0; // Получить количество жизней у персонажа virtualint getAttackLive() = 0; // Получить параметр атаки virtualint getResourceCount() = 0; // Получить количество ресурсов, требуемое для создания персонажа virtualbool attack(int attackLive) = 0; // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) };
#endif
Содержимоефайла army.h #include"archer.h" #include"horseman.h" #include"army_factory.h"
// Класс, содержащий всех воинов той или иной армии class Army { private: inttotalArcher; // Общеечислолучниковвармии int totalHorseman; // Общее число кавалеристов в армии int totalResource; // Общее число ресурсов в армии
Archer** archers; // Массив лучников в армии Horseman** horsemans; // Массив кавалеристов в армии
public: Army(ArmyFactory* ar, int colArcher, int colHorseman, int colResource); // Конструктор (принимает фабрику, которая будет создавать воинов, количество лучников, кавалеристов, которых нужно создать, а также количество ресурсов, которые есть для этого) // Если ресурсов недостаточно, то войны создаваться не будут ~Army(); // Деструктор - удаляет всех воинов
bool attack(Army* ar); // Атакует армию неприятеля void info(); // Выводит информацию о оставшихся в живых воинах армии int getTotalHorseman(); // Получает общее количество кавалеристов в армии int getTotalArcher(); // Получает общее количество лучников в армии int getTotalResource(); // Получает общее ресурсов в армии };
Содержимоефайла army_factory.h #ifndef _ARMY_FACTORY_ #define _ARMY_FACTORY_ 1
#include"archer.h" #include"horseman.h"
// Интерфейс для создания армии воинов class ArmyFactory { public: virtual Archer* createArcher() = 0; virtual Horseman* createHorseman() = 0; };
#endif Содержимоефайла carthaginian_archer.h #include"archer.h"
// Класс, представляющий собой лучника армии Карфагена class CarthaginianArcher : public Archer { public: CarthaginianArcher(); // Конструктор int getLive(); // Получить количество жизней у персонажа int getAttackLive(); // Получить параметр атаки int getResourceCount(); // Получить количество ресурсов, требуемое для создания персонажа bool attack(int attackLive); // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) }; Содержимоефайла carthaginian_army_factory.h #include"army_factory.h"
// Фабрика для создания воинов армии Карфагена class CarthaginianArmyFactory: public ArmyFactory { public: Archer* createArcher(); Horseman* createHorseman(); };
Содержимоефайла carthaginian_horseman.h #include"horseman.h"
// Класс, представляющий собой кавалериста армии Карфагена class CarthaginianHorseman : public Horseman { public: CarthaginianHorseman(); // Конструктор int getLive(); // Получить количество жизней у персонажа int getAttackLive(); // Получить параметр атаки int getResourceCount(); // Получить количество ресурсов, требуемое для создания персонажа bool attack(int attackLive); // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) };
Содержимое файла horseman.h #ifndef _HORSEMAN_ #define _HORSEMAN_ 1
// Интерфейс, представляющий собой абстрактного кавалериста class Horseman { protected: int totalLive; // Количествожизнейуперсонажа int attackLive; // Количество жизней, снимаемых при атаке int resourceCount; // Количество ресурсов, необходимое для производства лучника public: virtualint getLive() = 0; // Получить количество жизней у персонажа virtualint getAttackLive() = 0; // Получить параметр атаки virtualint getResourceCount() = 0; // Получить количество ресурсов, требуемое для создания персонажа virtualbool attack(int attackLive) = 0; // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) };
#endif
Содержимоефайла roman_archer.h #include"archer.h"
// Класс, представляющий собой лучника Римской армии class RomanArcher : public Archer { public: RomanArcher(); // Конструктор int getLive(); // Получить количество жизней у персонажа int getAttackLive(); // Получить параметр атаки int getResourceCount(); // Получить количество ресурсов, требуемое для создания персонажа bool attack(int attackLive); // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) };
Содержимоефайла roman_army_factory.h #include"army_factory.h"
// Фабрика для создания воинов Римской армии class RomanArmyFactory: public ArmyFactory { public: Archer* createArcher(); Horseman* createHorseman(); };
Содержимоефайла roman_horseman.h #include"horseman.h"
// Класс, представляющий собой кавалериста Римской армии class RomanHorseman : public Horseman { public: RomanHorseman(); // Конструктор int getLive(); // Получить количество жизней у персонажа int getAttackLive(); // Получить параметр атаки int getResourceCount(); // Получить количество ресурсов, требуемое для создания персонажа bool attack(int attackLive); // Атаковать персонаж (метод возвращает признак жизни персонажа после атаки - жив или нет, принимает атакующий параметр - сколько жизней отнять при атаке) };
Содержимоефайла army.cpp #include<iostream> #include"army.h"
usingnamespace std;
Army::Army(ArmyFactory* ar, int colArcher, int colHorseman, int colResource) { this -> totalArcher = 0; this -> totalHorseman = 0; this -> totalResource = colResource; this -> archers = new Archer*[colArcher]; this -> horsemans = new Horseman*[colHorseman];
// Создаемлучников for(int i=0; i<colArcher; i++) { // Попытаться создать лучника Archer* a = ar->createArcher(); // Если при этом количество потраченных ресурсов меньше доступного числа ресурсов, // то записываем созданного лучника в массив, иначе выходим из цикла if (a->getResourceCount() <= this -> totalResource) { this -> archers[this -> totalArcher] = a; this -> totalArcher++; // Уменьшаемколичестворесурсов this -> totalResource -= a->getResourceCount(); } else break; }
// Аналогичнодлякавалеристов for(int i=0; i<colHorseman; i++) { // Попытаться создать кавалериста Horseman* h = ar->createHorseman(); // Если при этом количество потраченных ресурсов меньше доступного числа ресурсов, // то записываем созданного лучника в массив, иначе выходим из цикла if (h->getResourceCount() <= this -> totalResource) { this -> horsemans[this -> totalHorseman] = h; this -> totalHorseman++; // Уменьшаемколичестворесурсов this -> totalResource -= h->getResourceCount(); } else break; } }
int Army::getTotalHorseman() { // Получает общее количество кавалеристов в армии returnthis -> totalHorseman; }
int Army::getTotalArcher() { // Получает общее количество лучников в армии returnthis -> totalArcher; }
int Army::getTotalResource() { // Получает общее ресурсов в армии returnthis -> totalResource; }
void Army::info() { // Выводит информацию о всех оставшихся в живых воинах cout <<"Лучники:"<< endl; for (int i = 0; i <this -> totalArcher; i++) cout <<"Лучник "<< (i+1) <<": осталось "<<this -> archers[i] -> getLive() <<" жизней"<< endl; cout <<"Кавалеристы:"<< endl; for (int i = 0; i <this -> totalHorseman; i++) cout <<"Кавалерист "<< (i+1) <<": осталось "<<this -> horsemans[i] -> getLive() <<" жизней"<< endl; }
bool Army::attack(Army* ar) { // Атакует армию неприятеля (ar) // возвращает true, если армия победила неприятельскую
// Каждый воин текущей армии (this) выбирает случайным образом воина из армии неприятеля (ar), после чего атакует его for (int i = 0; i <this -> totalArcher; i++) { int i1 = ar -> getTotalHorseman(); int i2 = ar -> getTotalArcher();
// Соперников неприятеля не осталось - армия победила if (i1 == 0 && i2 == 0) returntrue;
int randType; int randNum;
// Если остались только кавалеристы if (i1 != 0 && i2 == 0) { randType = 0; randNum = rand() % i1; } // Если остались только лучники if (i1 == 0 && i2 != 0) { randType = 1; randNum = rand() % i2; } // Если остались и те, и другие - тип воина выберем случайно if (i1 != 0 && i2 != 0) { randType = rand() % 2; if (randType == 0) randNum = rand() % i1; else randNum = rand() % i2; }
// Атакуем случайно выбранного воина bool murdered; if (randType == 0) murdered = ar -> horsemans[randNum] -> attack(this -> archers[i] -> getAttackLive()); else murdered = ar -> archers[randNum] -> attack(this -> archers[i] -> getAttackLive());
// Если воин погиб - удалить его из массива воинов if (murdered == true) { if (randType == 0) { delete ar -> horsemans[randNum]; for (int i3 = randNum; i3 < i1 - 1 ; i3++) ar -> horsemans[i3] = ar -> horsemans[i3 + 1]; ar -> totalHorseman --; } else { delete ar -> archers[randNum]; for (int i3 = randNum; i3 < i1 - 1 ; i3++) ar -> archers[i3] = ar -> archers[i3 + 1]; ar -> totalArcher --; } } }
// Все то же самое, но для кавалериста for (int i = 0; i <this -> totalHorseman; i++) { int i1 = ar -> getTotalHorseman(); int i2 = ar -> getTotalArcher();
// Соперников неприятеля не осталось - армия победила if (i1 == 0 && i2 == 0) returntrue;
int randType; int randNum;
// Если остались только кавалеристы if (i1 != 0 && i2 == 0) { randType = 0; randNum = rand() % i1; } // Если остались только лучники if (i1 == 0 && i2 != 0) { randType = 1; randNum = rand() % i2; } // Если остались и те, и другие - тип воина выберем случайно if (i1 != 0 && i2 != 0) { randType = rand() % 2; if (randType == 0) randNum = rand() % i1; else randNum = rand() % i2; }
// Атакуем случайно выбранного воина bool murdered; if (randType == 0) murdered = ar -> horsemans[randNum] -> attack(this -> horsemans[i] -> getAttackLive()); else murdered = ar -> archers[randNum] -> attack(this -> horsemans[i] -> getAttackLive());
// Если воин погиб - удалить его из массива воинов if (murdered == true) { if (randType == 0) { delete ar -> horsemans[randNum]; for (int i3 = randNum; i3 < i1 - 1 ; i3++) ar -> horsemans[i3] = ar -> horsemans[i3 + 1]; ar -> totalHorseman --; } else { delete ar -> archers[randNum]; for (int i3 = randNum; i3 < i1 - 1 ; i3++) ar -> archers[i3] = ar -> archers[i3 + 1]; ar -> totalArcher --; } } }
returnfalse; }
Содержимоефайла carthaginian_archer.cpp #include"carthaginian_archer.h"
CarthaginianArcher::CarthaginianArcher() { this->totalLive = 50; // Текущее количество жизней лучника армии Кархагена this->attackLive = 7; // При каждой атаке персонажи данного типа будут отнимать указанное количество жизней this->resourceCount = 24; // Количество ресурсов, необходимое для производства кавалериста Римской армии }
int CarthaginianArcher::getLive() { returnthis->totalLive; }
int CarthaginianArcher::getAttackLive() { returnthis->attackLive; }
int CarthaginianArcher::getResourceCount() { returnthis->resourceCount; }
bool CarthaginianArcher::attack(int attackLive) { // Нас атаковали с параметром attackLive // Отнимаем у персонажа переданное количество жизней this->totalLive -= attackLive;
if (this->totalLive <= 0) returntrue; // Персонажпогиб else returnfalse; // Персонажещеживет }
Содержимоефайла carthaginian_army_factory.cpp #include"carthaginian_archer.h" #include"carthaginian_horseman.h" #include"carthaginian_army_factory.h"
Archer* CarthaginianArmyFactory::createArcher() { returnnew CarthaginianArcher(); }
Horseman* CarthaginianArmyFactory::createHorseman() { returnnew CarthaginianHorseman(); }
Содержимоефайла carthaginian_horseman.cpp #include"carthaginian_horseman.h"
CarthaginianHorseman::CarthaginianHorseman() { this->totalLive = 120; // ТекущееколичествожизнейкавалеристаармииКархагена this->attackLive = 15; // При каждой атаке персонажи данного типа будут отнимать указанное количество жизней this->resourceCount = 35; // Количество ресурсов, необходимое для производства кавалериста Римской армии }
int CarthaginianHorseman::getLive() { returnthis->totalLive; }
int CarthaginianHorseman::getAttackLive() { returnthis->attackLive; }
int CarthaginianHorseman::getResourceCount() { returnthis->resourceCount; }
bool CarthaginianHorseman::attack(int attackLive) { // Нас атаковали с параметром attackLive // Отнимаем у персонажа переданное количество жизней this->totalLive -= attackLive;
if (this->totalLive <= 0) returntrue; // Персонажпогиб else returnfalse; // Персонажещеживет }
Содержимоефайла main.cpp #include<iostream> #include<Windows.h>
#include"roman_army_factory.h" #include"carthaginian_army_factory.h" #include"army.h"
usingnamespace std;
// Главнаяфункция int main() { SetConsoleOutputCP(1251);
// СоздаемРимскуюармию int colArcher; int colHoresman; int colResource; cout <<"РИМСКАЯ АРМИЯ - ВВОД ДАННЫХ"<< endl; cout <<" Число лучников: "; cin >> colArcher; cout <<" Число кавалеристов: "; cin >> colHoresman; cout <<" Количество ресурсов: "; cin >> colResource; // СоздаемфабрикудляРима ArmyFactory* rimf = new RomanArmyFactory(); // СоздаемармиюРима Army* rim = new Army(rimf, colArcher, colHoresman, colResource);
// Выводим параметры созданной армии cout <<"РИМСКАЯ АРМИЯ - СОЗДАНО"<< endl; cout <<" Числолучников: "<< rim ->getTotalArcher() << endl; cout <<" Числокавалеристов: "<< rim -> getTotalHorseman() << endl; cout <<" Осталосьресурсов: "<< rim -> getTotalResource() << endl;
// ******************
// Создаем армию Карфагена cout <<"АРМИЯ КАРФАГЕНА - ВВОД ДАННЫХ"<< endl; cout <<" Число лучников: "; cin >> colArcher; cout <<" Число кавалеристов: "; cin >> colHoresman; cout <<" Количество ресурсов: "; cin >> colResource; // Создаем фабрику для Карфагена ArmyFactory* carf = new CarthaginianArmyFactory(); // СоздаемармиюКарфагена Army* car = new Army(carf, colArcher, colHoresman, colResource);
// Выводим параметры созданной армии cout <<"АРМИЯ КАРФАГЕНА - СОЗДАНО"<< endl; cout <<" Числолучников: "<< car ->getTotalArcher() << endl; cout <<" Числокавалеристов: "<< car -> getTotalHorseman() << endl; cout <<" Осталосьресурсов: "<< car -> getTotalResource() << endl;
cout << endl <<"******НАЧАЛОИГРЫ*******"<< endl << endl; while (true) { cout <<"1 - Атаковать Римскую Армию"<< endl; cout <<"2 - Атаковать Армию Карфагена"<< endl; cout <<"3 - Выход"<< endl; int command; cin >> command;
if (command == 1) { if (car -> attack(rim)) cout<<"АрмияКарфагена: УРА, ПОБЕДА!"<<endl; else { cout <<"Армия Карфагена: - Генерал, мы пока не победили, но нанесли ощутимый урон сопернику"<< endl; cout <<"Армия Карфагена: - И какой?"<< endl; cout <<"Армия Карфагена: - Вот таблица, можете сами посмотреть"<< endl; cout <<"Состав Римской армии на данный момент"<< endl; rim -> info(); } }
if (command == 2) { if (rim -> attack(car)) cout<<"РимскаяАрмия : УРА, ПОБЕДА!"<< endl; else { cout <<"Римская Армия: - Полководец, мы сделали все что смогли, но победить Карфагена не удалось. Но мы нанесли им урон"<< endl; cout <<"Римская Армия: - И какой?"<< endl; cout <<"Римская Армия: - Вот таблица, можете сами посмотреть"<< endl; cout <<"Состав Армии Карфагена на данный момент"<< endl; car -> info(); } }
if (command == 3) break; } }
Содержимоефайла roman_archer.cpp #include"roman_archer.h"
RomanArcher::RomanArcher() { this->totalLive = 60; // ТекущееколичествожизнейлучникаРимскойармии this->attackLive = 5; // При каждой атаке персонажи данного типа будут отнимать указанное количество жизней this->resourceCount = 20; // Количество ресурсов, необходимое для производства кавалериста Римской армии }
int RomanArcher::getLive() { returnthis->totalLive; }
int RomanArcher::getAttackLive() { returnthis->attackLive; }
int RomanArcher::getResourceCount() { returnthis->resourceCount; }
bool RomanArcher::attack(int attackLive) { // Нас атаковали с параметром attackLive // Отнимаем у персонажа переданное количество жизней this->totalLive -= attackLive;
if (this->totalLive <= 0) returntrue; // Персонажпогиб else returnfalse; // Персонажещеживет }
Содержимоефайла roman_army_factory.cpp #include"roman_archer.h" #include"roman_horseman.h" #include"roman_army_factory.h"
Archer* RomanArmyFactory::createArcher() { returnnew RomanArcher(); }
Horseman* RomanArmyFactory::createHorseman() { returnnew RomanHorseman(); }
Содержимоефайла roman_horseman.cpp #include"roman_horseman.h"
RomanHorseman::RomanHorseman() { this->totalLive = 100; // ТекущееколичествожизнейкавалеристаРимскойармии this->attackLive = 12; // При каждой атаке персонажи данного типа будут отнимать указанное количество жизней this->resourceCount = 30; // Количество ресурсов, необходимое для производства кавалериста Римской армии }
int RomanHorseman::getLive() { returnthis->totalLive; }
int RomanHorseman::getAttackLive() { returnthis->attackLive; }
int RomanHorseman::getResourceCount() { returnthis->resourceCount; }
bool RomanHorseman::attack(int attackLive) { // Нас атаковали с параметром attackLive // Отнимаем у персонажа переданное количество жизней this->totalLive -= attackLive;
if (this->totalLive <= 0) returntrue; // Персонажпогиб else returnfalse; // Персонажещеживет }
|
|||
|