1
\$\begingroup\$

I am trying to make all the creational design patterns and I'm having some trouble with the abstract factory method. I normally program in Python, however, I had heard C++ was good for really having to understand design patterns explicitly, which is proving to be right, err.

I'm basically following this guide on Tutorials Point.

My question is how would I change my current code to correctly implement the abstract factory method in C++ with a factory producer as I believe its something to do with my Factory Producer extra layer of abstraction that is causing my issues. I have included all my code.

I tried to make a simple diagram to explain better but it's not the most formal UML but is essentially what I would like to make. My main.cpp file should illustrate better the functionality I'm trying to understand how to make.

Abstract Factory UML Diagram

P.s. I'm just trying to improve to apply for jobs so please let me know if you have any feedback on writing better SO questions, coding style, variable naming or even C++ conventions.

Main

main.cpp - Main implementation file

Tests creating an abstract factory, abstract sword and abstract warrior.

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

Abstract Factory Class

abstractfactory.h - Abstract Factory header file

#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 implementation file

#include "abstractfactory.h"

AbstractFactory::~AbstractFactory(){}

Factory Producer Class

factoryproducer.h - Factory Producer header file

#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 implementation file

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

Abstract Warrior Class

warrior.h - Abstract Warrior header file

#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 getPicture() = 0;
};

#endif // WARRIOR_H

warrior.cpp - Abstract Warrior implementation file

#include "warrior.h"

Warrior::~Warrior(){}

Abstract Sword Class

sword.h - Abstract Sword header file

#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 implementation file

#include "sword.h"

Sword::~Sword(){}

Concrete TinySword Class

tinysword.h - Concrete Tiny Sword header file

#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 - Concrete Tiny Sword implementation file

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

Concrete Normal Sword

normalsword.h - Concrete Normal Sword header file

#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 implementation file

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

Concrete Large Sword Class

largesword.h - Concrete Large Sword header file

#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 implementation file

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

Concrete Giant Sword Class

giantsword.h - Concrete Giant Sword header file

#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 - Concrete Giant Sword implementation file

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

Concrete Tiny Warrior Class

tinywarrior.h - Concrete Tiny Warrior header file

#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 - Concrete Tiny Warrior implementation file

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

Concrete Normal Warrior Class

normalwarrior.h - Concrete Normal Warrior header file

#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 Concrete Normal Warrior implementation

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

Concrete Large Warrior Class

largewarrior.h Concrete Large Warrior header file

#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 implementation file

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

Concrete Giant Warrior Class

giantwarrior.h - Concrete Giant Warrior header file

#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 implementation file

#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;
}
\$\endgroup\$
  • \$\begingroup\$ Besides the Abstract Facory pattern, you might be interested to also implement the Decorator Pattern. As it's not formal UML, your class diagram is pretty useless. \$\endgroup\$ – πάντα ῥεῖ Apr 2 '17 at 10:31
  • \$\begingroup\$ @πάνταῥεῖ I'll also check out the Decorator Pattern however, I'd like to finish this implementation first. I'll attempt to fix up the class diagram to add implements, extends, uses in it. It however is aligned with what is done in this tutorial which I just saw had an UML diagram I could have copied tutorialspoint.com/design_pattern/abstract_factory_pattern.htm \$\endgroup\$ – joshuatvernon Apr 2 '17 at 10:36
  • \$\begingroup\$ @πάνταῥεῖ thank you for your feedback, I fixed up the class diagram to better explain what I am trying to achieve. \$\endgroup\$ – joshuatvernon Apr 2 '17 at 11:16
  • \$\begingroup\$ Why not simply using formal UML for the diagram, such it would be clear for everyone? UML is a pretty essential skill for any programmer in the OOP world nowadays. \$\endgroup\$ – πάντα ῥεῖ Apr 2 '17 at 11:17
  • \$\begingroup\$ I think your understanding of abstract factory is wrong. Each implementation of the abstract factory, implements all the functionality. In your example diagram, you don't have a sword factory and a warrior factory. You would rather have a British factory that made british swords and warriors and a French factory that made french swords and french warriors. \$\endgroup\$ – Martin York Apr 2 '17 at 13:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.