Wzorzec Fabryka abstrakcyjna i Metoda wytwórcza C++/Qt

Zastosowanie

Fabryka abstrakcyjna (ang. abstract factory) to kreacyjny wzorzec metody wytwórczej dostarcza abstrakcji do tworzenia obiektów nieokreślonych, ale powiązanych typów. Umożliwia także dziedziczącym klasom decydowanie jakiego typu ma to być obiekt. Jest on często używany wraz ze wzorce metody wytwórczej lub inaczej nazywanej metody fabrykującej (ang. factory method), która umożliwia zwracanie obiektów, lub przypisywanie im właściwości w zależności od parametru wysłanego.

Fabryka abstrakcyjna

Wskazówki praktyczne

Wzorzec jest stosowany wówczas gdy chcemy ujednolicić interfejs i uniezależnić interfejs od implementacji i składania obiektów. W przypadku metody wytwórczej stosujemy ją wówczas gdy nie wiemy jakie obiekty będą tworzone podczas używania programu (np. będzie delegatem lub tworzona przez wybór użytkownika). Dobrym przykładem jest generowania poprzez klasy konkretne plików html, pdf lub zwykłego tekstu, za pomocą wspólnego interfejsu (fabryki abstrakcyjnej).

Zalety i wady

Zalety

  • Odseparowanie klas konkretnych poprzez posługiwanie się interfejsami abstrakcyjnymi.
  • Łatwość rzutowania pomiędzy obiektami pochodnymi.
  • Spójność klas, w sytuacji gdy pożądane jest, aby klasy produkty były z określonej rodziny, fabryka bardzo dobrze to zapewnia.
  • Łatwość utrzymania kodu po dodaniu klasy pochodnej, oraz łatwe dodawanie implementacji logiki nowych klas pochodnych.

Wady:

  • Trudność w rozszerzaniu o nowe funkcjonalności klas pochodnych, spowodowana koniecznością rozszerzania interfejsów fabryki.
#include <QDebug>
#include <QString>

using namespace std;

// Abstract base class
class Oferta {
public:
    virtual const QString getOfertaPodstawowa() = 0;
    virtual const QString getDodatki() = 0;

    void print() {
        qDebug() << getOfertaPodstawowa() <<  getDodatki();
    }
    virtual ~Oferta(){qDebug() <<"Oferta usunięta";}

};

// Klasa konkretna
class OszczednaOferta : public Oferta {
public:
   const QString getOfertaPodstawowa() {
        return "Abonament 20zł";
    }

   const QString getDodatki() {
        return "Pakiet 60 minut i 30 sms-ów";
    }
   ~OszczednaOferta(){ qDebug() <<"Oszczędna oferta usunięta"; }
};

// Klasa konkretna
class SredniaOferta : public Oferta {
public:
    const QString getOfertaPodstawowa()
    {
        return "Abonament 50zł";
    }

   const QString getDodatki()
   {
        return "Pakiet 1000 minut i 1000 sms-ów";
    }
   ~SredniaOferta(){ qDebug() <<"Średnia oferta usunięta";}
};

// Klasa konkretna
class DrogaOferta : public Oferta {
public:
   const QString getOfertaPodstawowa() {
        return "Abonament 40zł";
    }

   const QString getDodatki() {
        return "Pakiet 300 minut i 200 sms-ów";
    }
   ~DrogaOferta(){ qDebug() <<"Droga oferta usunięta";}
};

// Abstract Factory returning a Oferta
class OfertaFactory {
public:
    Oferta* getOferta(const QString type)
    {
        if ( type == "Oszczędna" ) return new OszczednaOferta();
        else if ( type == "Średnia" ) return new SredniaOferta();
        else if ( type == "Droga" ) return new DrogaOferta();
        return NULL;
    }
    ~OfertaFactory(){

}

};

int main()
{
    OfertaFactory* myFactory = new OfertaFactory();

    Oferta* myOferta1 = myFactory->getOferta("Oszczędna");
    myOferta1->print();

    Oferta* myOferta2 = myFactory->getOferta("Średnia");
    myOferta2->print();

    Oferta* myOferta3 = myFactory->getOferta("Droga");
    myOferta3->print();

    delete myOferta1;
    delete myOferta2;
    delete myOferta3;

    return 0;
}

Wyjście programu:

"Abonament 20zł" "Pakiet 60 minut i 30 sms-ów"
"Abonament 50zł" "Pakiet 1000 minut i 1000 sms-ów"
"Abonament 40zł" "Pakiet 300 minut i 200 sms-ów"
Oszczędna oferta usunięta
Oferta usunięta
Średnia oferta usunięta
Oferta usunięta
Droga oferta usunięta
Oferta usunięta

Przykład 2

#include <iostream>
#include <QtCore>


using namespace std;

class Shape {
  public:
    Shape() {
      id_ = total_++;
    }
    virtual void draw() = 0;
  protected:
    int id_;
    static int total_;
};
int Shape::total_ = 0;

class Circle : public Shape {
  public:
    void draw() {
      cout << "circle " << id_ << ": draw" << endl;
    }
};
class Square : public Shape {
  public:
    void draw() {
      cout << "square " << id_ << ": draw" << endl;
    }
};
class Ellipse : public Shape {
  public:
    void draw() {
      cout << "ellipse " << id_ << ": draw" << endl;
    }
};
class Rectangle : public Shape {
  public:
    void draw() {
      cout << "rectangle " << id_ << ": draw" << endl;
    }
};

class Factory {
  public:
    virtual Shape* createCurvedInstance() = 0;
    virtual Shape* createStraightInstance() = 0;
};

class SimpleShapeFactory : public Factory {
  public:
    Shape* createCurvedInstance() {
      return new Circle;
    }
    Shape* createStraightInstance() {
      return new Square;
    }
};
class RobustShapeFactory : public Factory {
  public:
    Shape* createCurvedInstance()   {
      return new Ellipse;
    }
    Shape* createStraightInstance() {
      return new Rectangle;
    }
};

int main() {
#ifdef Q_OS_LINUX
  Factory* factory = new SimpleShapeFactory;
#elif Q_OS_ANDROID
  Factory* factory = new RobustShapeFactory;
#endif
  Shape* shapes[3];

  shapes[0] = factory->createCurvedInstance();   // shapes[0] = new Ellipse;
  shapes[1] = factory->createStraightInstance(); // shapes[1] = new Rectangle;
  shapes[2] = factory->createCurvedInstance();   // shapes[2] = new Ellipse;

  for (int i=0; i < 3; i++) {
    shapes[i]->draw();
  }
  for (int i=0; i < 3; i++)
    delete shapes[i];
}