使用 Qt Creator 在 C++ 中实现抽象工厂设计模式

Abstract Factory Design Pattern implementation in C++ using Qt Creator

我正在尝试制作所有创造性的设计模式,但我在使用抽象工厂方法时遇到了一些麻烦。我通常在 Python 中编程,但是,我听说 C++ 非常适合真正必须明确理解设计模式,事实证明这是正确的,错误。

我基本上是在 Tutorials Point 上遵循本指南。

我的问题是如何更改我当前的代码以使用工厂生产者在 C++ 中正确实施抽象工厂方法,因为我认为它与导致我的问题的工厂生产者额外抽象层有关。我已经包含了我所有的代码。

我试图制作一个简单的图表来更好地解释,但这不是最正式的 UML,但本质上是我想制作的。我的 main.cpp 文件应该更好地说明我试图了解如何制作的功能。

P.s。我只是想改进以申请工作,所以如果您对编写更好的 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();
}

抽象工厂Class

abstractfactory.h - 抽象工厂头文件

#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抽象工厂实现文件

#include "abstractfactory.h"

AbstractFactory::~AbstractFactory(){}

工厂生产者Class

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;
}

抽象战士Class

warrior.h - 抽象战士头文件

#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(){}

抽象剑Class

sword.h - 抽象剑头文件

#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 - 抽象剑实现文件

#include "sword.h"

Sword::~Sword(){}

混凝土 TinySword Class

tinysword.h - Concrete Tiny Sword 头文件

#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 - Concrete Normal Sword 头文件

#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 - 具体的普通剑实现文件

#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;
}

混凝土大剑Class

largesword.h - Concrete Large Sword 头文件

#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 - 具体大剑实现文件

#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;
}

混凝土巨剑Class

giantsword.h - Concrete Giant Sword 头文件

#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;
}

混凝土小战士Class

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;
}

具体普通战士Class

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

普通warrior.cpp具体普通战士实现

#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;
}

混凝土大战士Class

大warrior.h具体大武士头文件

#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

大warrior.cpp具体的大战士实现文件

#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;
}

混凝土巨人战士Class

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 - 具体的巨人战士实现文件

#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 中给出的示例具有误导性。 例如,如果调用 createSword,您的 WarriorFactory return 是什么?返回 nullptr 不是一个选项,因为:

void doSomethingWithFactory(AbstractFactory* f)
{
    Warrior* w = f->createWarrior();
    Sword* s = f->createSword();
}

你实际上需要知道你是否被赋予了一个战士或一个剑工厂,因此你没有抽象任何东西。

我编写了一个示例,该示例使用创建怪物和战士的抽象 EnemyFactory。根据具体工厂的不同,这些敌人或强或弱。 EnemyFactory 这个工厂总是制造敌人,但他们的属性因具体工厂而异。

显然我不能谈论你未来潜在的雇主,但我个人不会对你编写的代码感到兴奋。不管它是否按预期工作,它都存在许多问题:

  • 它太冗长了,太多的代码做的太少了,这有几个含义——你作为开发人员浪费了时间,你产生的代码不干净、不简洁而且很难维持

  • 类似cout<<tinySword->getName().toStdString()<<endl;的东西-不要那样做,使用那个space吧

  • 要么使用 Qt,要么使用 std:: - 没有必要将两者混合,进行冗余转换等等

  • 你的代码涉及一堆字符串比较,这些操作相当慢,最好尽可能避免,如果你正在做一个模块化的插件架构,字符串是有意义的,插件实现核心中不存在但在您的特定场景中不存在的类型

  • 我们真的需要为每个微小的变化单独 class 吗?小剑、大剑、巨剑?只有一个 Sword class,有一个很好的 uint size; 成员和一个大小枚举怎么样?

  • 您的场景也不完全需要抽象工厂,您最好使用单一的多功能工厂,尤其是在游戏对象管理的情况下

  • 比较QStringnullptr,真的吗?

  • 编写 getter 和 setter - 这很酷,对吧?我的意思是为什么简单地拥有它们 public,因为您同时拥有读写访问器,当您可以将它们设为私有时,并编写额外的代码以使私有成员成为事实上的 public。这就是 OOP 的全部内容......与流行的看法相反,我认为只有当它涉及比直接成员访问更复杂的时候,编写 setter 和 getter 才是合理的。

  • 您只有名称和图片的 getter,这意味着它们是静态构造。在那种情况下,为什么还要将它们存储为成员变量?不必要的内存开销?

您的代码长城似乎可以很容易地简化为功能相同、性能更好、可读性和可维护性更高的代码。