Я пытаюсь создать все шаблоны творческого проектирования, и у меня возникли некоторые проблемы с методом абстрактной фабрики. Обычно я программирую на Python, но слышал, что C ++ хорош для того, чтобы действительно понимать шаблоны проектирования явно, что оказывается правильным, ошибочно.
Я в основном следую этому руководству Учебное пособие.
Мой вопрос заключается в том, как бы изменить текущий код для правильной реализации метода абстрактной фабрики в C ++ с фабричным производителем, поскольку я считаю, что это как-то связано с дополнительным уровнем абстракции моего Factory Producer, который вызывает мои проблемы. Я включил весь свой код.
Я попытался сделать простую диаграмму, чтобы объяснить лучше, но это не самый формальный UML, но по сути это то, что я хотел бы сделать. мой main.cpp
Файл должен лучше иллюстрировать функционал, который я пытаюсь понять, как сделать.
Постскриптум Я просто пытаюсь улучшить работу, чтобы подать заявку на работу, поэтому, пожалуйста, дайте мне знать, если у вас есть какие-либо отзывы о написании лучших вопросов SO, стиля кодирования, именования переменных или даже соглашений C ++.
main.cpp — Основной файл реализации
Испытания создания абстрактной фабрики, абстрактного меча и абстрактного воина.
#include "factoryproducer.h"
using namespace std;
int main(int argc, char *argv[]) {
AbstractFactory* warriorFactory = FactoryProducer::createFactory("warriorfactory");
Warrior* tinyWarrior = warriorFactory->createWarrior("tinywarrior");
Warrior* normalWarrior = warriorFactory->createWarrior("normalwarrior");
Warrior* largeWarrior = warriorFactory->createWarrior("largewarrior");
Warrior* giantWarrior = warriorFactory->createWarrior("giantwarrior");
cout<<tinyWarrior->getName().toStdString()<<endl;
cout<<normalWarrior->getName().toStdString()<<endl;
cout<<largeWarrior->getName().toStdString()<<endl;
cout<<giantWarrior->getName().toStdString()<<endl;
AbstractFactory* SwordFactory = FactoryProducer::createFactory("swordfactory");
Sword* tinySword = swordFactory->createSword("tinysword");
Sword* normalSword = swordFactory->createSword("normalsword");
Sword* largeSword = swordFactory->createSword("largesword");
Sword* giantSword = swordFactory->createSword("giantsword");
cout<<tinySword->getName().toStdString()<<endl;
cout<<normalSword->getName().toStdString()<<endl;
cout<<largeSword->getName().toStdString()<<endl;
cout<<giantSword->getName().toStdString()<<endl;
return a.exec();
}
abstractfactory.h — Заголовочный файл Abstract Factory
#ifndef ABSTRACTFACTORY_H
#define ABSTRACTFACTORY_H
#include "warrior.h"#include "sword.h"#include <QString>
class AbstractFactory {
public:
// Public Methods
~AbstractFactory();
virtual Warrior* createWarrior(QString warriorType) = 0;
virtual Sword* createSword(QString swordType) = 0;
};
#endif // ABSTRACTFACTORY_H
abstractfactory.cpp Файл реализации Abstract Factory
#include "abstractfactory.h"
AbstractFactory::~AbstractFactory(){}
factoryproducer.h — Заголовочный файл Factory Producer
#ifndef FACTORYPRODUCER_H
#define FACTORYPRODUCER_H
#include "abstractfactory.h"#include "warriorfactory.h"#include "swordfactory.h"#include <QString>
class FactoryProducer {
public:
// Public Methods
static AbstractFactory* createFactory(QString factoryType);
};
#endif // FACTORYPRODUCER_H
factoryproducer.cpp — Файл реализации Factory Producer
#include "factoryproducer.h"
AbstractFactory* AbstractFactory::createFactory(QString factoryType) {
if (factoryType == nullptr) {
return nullptr;
}
if (QString::compare(factoryType, "WARRIORFACTORY", Qt::CaseInsensitive) == 0) {
return new WarriorFactory();
}
if (QString::compare(factoryType, "SWORDFACTORY", Qt::CaseInsensitive) == 0) {
return new SwordFactory();
}
return nullptr;
}
warrior.h — Заголовочный файл Abstract Warrior
#ifndef WARRIOR_H
#define WARRIOR_H
#include "tinywarrior.h"#include "normalwarrior.h"#include "largewarrior.h"#include "giantwarrior.h"#include <QString>
class Warrior {
public:
// Public Methods
~Warrior();
virtual QString getName() = 0;
virtual QString getPicture() = 0;
};
#endif // WARRIOR_H
warrior.cpp — Файл реализации Abstract Warrior
#include "warrior.h"
Warrior::~Warrior(){}
sword.h — Заголовочный файл Abstract Sword
#ifndef SWORD_H
#define SWORD_H
#include "tinysword.h"#include "normalsword.h"#include "largesword.h"#include "giantsword.h"#include <QString>
class Sword {
public:
// Public Methods
~Sword();
virtual QString getName() = 0;
virtual QString getPicture() = 0;
};
#endif // SWORD_H
sword.cpp — Файл реализации Abstract Sword
#include "sword.h"
Sword::~Sword(){}
tinysword.h — Заголовочный файл «Конкретный крошечный меч»
#ifndef TINYSWORD_H
#define TINYSWORD_H
#include "sword.h"
class TinySword : public Sword {
public:
// Public Methods
TinySword();
~TinySword();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // TINYSWORD_H
tinysword.cpp — Конкретный файл реализации Tiny Sword
#include "tinysword.h"
TinySword::TinySword(){
m_name = "Tiny Sword";
m_picture = "";
}
TinySword::~TinySword(){}
QString TinySword::getName() {
return m_name;
}
QString TinySword::getPicture() {
return m_picture;
}
normalsword.h — Заголовочный файл «Конкретный нормальный меч»
#ifndef NORMALSWORD_H
#define NORMALSWORD_H
#include "sword.h"
class NormalSword : public Sword {
public:
// Public Methods
NormalSword();
~NormalSword();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // NORMALSWORD_H
normalsword.cpp — Файл реализации Concrete Normal Sword
#include "normalsword.h"
NormalSword::NormalSword() {
m_name = "Normal Sword";
m_picture = "";
}
NormalSword::~NormalSword(){}
QString NormalSword::getName() {
return m_name;
}
QString NormalSword::getPicture() {
return m_picture;
}
largesword.h — Заголовочный файл «Конкретный большой меч»
#ifndef LARGESWORD_H
#define LARGESWORD_H
#include "sword.h"
class LargeSword : public Sword {
public:
// Public Methods
LargeSword();
~LargeSword();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // LARGESWORD_H
largesword.cpp — Файл реализации Concrete Large Sword
#include "largesword.h"
LargeSword::LargeSword() {
m_name = "Large Sword";
m_picture = "";
}
LargeSword::~LargeSword(){}
QString LargeSword::getName() {
return m_name;
}
QString LargeSword::getPicture() {
return m_picture;
}
giantsword.h — Заголовочный файл «Конкретный гигантский меч»
#ifndef GIANTSWORD_H
#define GIANTSWORD_H
#include "sword.h"
class GiantSword : public Sword {
public:
// Public Methods
GiantSword();
~GiantSword();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // GIANTSWORD_H
giantsword.cpp — Файл реализации Бетонного Гигантского Меча
#include "giantsword.h"
GiantSword::GiantSword() {
m_name = "Giant Sword";
m_picture = "";
}
GiantSword::~GiantSword(){}
QString GiantSword::getName() {
return m_name;
}
QString GiantSword::getPicture() {
return m_picture;
}
tinywarrior.h — Конкретный заголовочный файл Tiny Warrior
#ifndef TINYWARRIOR_H
#define TINYWARRIOR_H
#include "warrior.h"
class TinyWarrior : public Warrior {
public:
// Methods
TinyWarrior();
~TinyWarrior();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // TINYWARRIOR_H
tinywarrior.cpp — Конкретный файл реализации Tiny Warrior
#include "tinywarrior.h"
TinyWarrior::TinyWarrior(){
m_name = "Tiny Warrior";
m_picture = ":/images/tiny-warrior.png";
}
TinyWarrior::~TinyWarrior(){}
QString TinyWarrior::getName() {
return m_name;
}
QString TinyWarrior::getPicture() {
return m_picture;
}
normalwarrior.h — Конкретный заголовочный файл Normal Warrior
#ifndef NORMALWARRIOR_H
#define NORMALWARRIOR_H
#include "warrior.h"
class NormalWarrior : public Warrior {
public:
// Public Methods
NormalWarrior();
~NormalWarrior();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // NORMALWARRIOR_H
normalwarrior.cpp Конкретная реализация Normal Warrior
#include "normalwarrior.h"
NormalWarrior::NormalWarrior() {
m_name = "Normal Warrior";
m_picture = ":/images/normal-warrior.png";
}
NormalWarrior::~NormalWarrior(){}
QString NormalWarrior::getName() {
return m_name;
}
QString NormalWarrior::getPicture() {
return m_picture;
}
largewarrior.h Заголовочный файл Concrete Large Warrior
#ifndef LARGEWARRIOR_H
#define LARGEWARRIOR_H
#include "warrior.h"
class LargeWarrior : public Warrior {
public:
// Methods
LargeWarrior();
~LargeWarrior();
QString getName();
QString getPicture();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // LARGEWARRIOR_H
largewarrior.cpp Файл реализации Concrete Large Warrior
#include "largewarrior.h"
LargeWarrior::LargeWarrior(){
m_name = "Large Warrior";
m_picture = ":/images/large-warrior.png";
}
LargeWarrior::~LargeWarrior(){}
QString LargeWarrior::getName() {
return m_name;
}
QString LargeWarrior::getPicture() {
return m_picture;
}
giantwarrior.h — Заголовочный файл Concrete Giant Warrior
#ifndef GIANTWARRIOR_H
#define GIANTWARRIOR_H
#include "warrior.h"
class GiantWarrior : public Warrior {
public:
// Methods
GiantWarrior();
~GiantWarrior();
QString getName();
QString getPicture();
void setXPosition(int x);
int getXPosition();
private:
// Private Member Variables
QString m_name;
QString m_picture;
};
#endif // GIANTWARRIOR_H
giantwarrior.cpp — Файл реализации Concrete Giant Warrior
#include "giantwarrior.h"
GiantWarrior::GiantWarrior(){
m_name = "Giant Warrior";
m_picture = ":/images/giant-warrior.png";
}
GiantWarrior::~GiantWarrior(){}
QString GiantWarrior::getName() {
return m_name;
}
QString GiantWarrior::getPicture() {
return m_picture;
}
Данный пример из TutorialsPoint вводит в заблуждение.
Например, что возвращает ваш WarriorFactory, если вызывается createSword? Возврат nullptr не вариант из-за этого:
void doSomethingWithFactory(AbstractFactory* f)
{
Warrior* w = f->createWarrior();
Sword* s = f->createSword();
}
На самом деле вам нужно знать, был ли вам дан воин или фабрика мечей, и поэтому вы ничего не абстрагируете.
Я кодировал пример, который использует абстрактный EnemyFactory, который создает монстров и воинов. В зависимости от конкретной фабрики эти враги бывают сильными или слабыми.
EnemyFactory
Эта фабрика всегда создает врагов, но их атрибуты различаются в зависимости от конкретной фабрики.
Очевидно, я не могу говорить о вашем потенциальном будущем работодателе, но лично я не был бы в восторге от кода, который вы производите. Независимо от того, работает ли он по назначению или нет, с ним возникает ряд проблем:
это слишком многословно, слишком много кода, который делает слишком мало, это имеет несколько последствий — вы теряете время как разработчик, вы создаете код, который не является чистым и кратким, и который будет трудно поддерживать
такие вещи, как cout<<tinySword->getName().toStdString()<<endl;
— не делай этого, используй пробел
либо используйте Qt, либо используйте std::
— нет смысла смешивать два, делать избыточные преобразования и так далее
Ваш код включает в себя множество сравнений строк, это довольно медленные операции, которых лучше избегать, когда это возможно, строки имеют смысл, если вы используете модульную архитектуру плагинов, где плагины реализуют типы, которых нет в ядре, но не в вашем конкретном сценарии
нам действительно нужен отдельный класс для каждого крошечного варианта? Маленький меч, большой меч, огромный меч? Как насчет одного Sword
класс, с хорошим uint size;
член и размер перечисления?
ваш сценарий также не требует абстрактных фабрик, вам лучше использовать одну универсальную фабрику, особенно в случае управления игровыми объектами
сравнивая QString
в nullptr
, действительно?
писать геттеры и сеттеры — теперь это круто, верно? Я имею в виду, почему просто сделать их общедоступными, поскольку у вас есть средства доступа для чтения и записи, когда вы можете сделать их приватными, и написать дополнительный код, чтобы сделать приватный член де-факто публичным. Вот что такое ООП … Вопреки распространенному мнению, я бы сказал, что написание сеттеров и геттеров оправдано только тогда, когда это связано с большей сложностью, чем прямой доступ к членам.
у вас есть только геттеры для имени и изображения, подразумевая, что это статические конструкции. В таком случае, зачем даже хранить их как переменные-члены? Излишняя память?
Казалось бы, ваша огромная стена кода легко может быть сведена к чему-то столь же функциональному, гораздо более эффективному, гораздо более читабельному и обслуживаемому.