Narzędzia użytkownika

Narzędzia witryny


fabryka_abstrakcyjna

Abstract factory pattern (Fabryka abstrakcyjna)

/*************************************************************************************      
 *                                                               Michał Chodkiewicz  *
 * Wzorzec:         fabryka abstrakcyjna (abstract factory)                          *
 *                                                                                   *
 * Zastosowanie:    Wzorzec ten umożliwia łatwe wprowadzanie zmian w zakresie klas   *
 *                  używanych w kodzie, co umożliwia pisanie kodu, np: na kilka      * 
 *                  platform jednocześnie, czy łatwiejsze zmienianie kodu wewnątrz   *
 *                  klasy bibliotecznej.                                             *
 *                                                                                   *   
 *   Opis:          Fabryka abstrakcyjna, zwykle tworzona jako interfejs, w języku   *
 *                  c++ jest implementowana za pomocą klasy abstrakcyjnej. Klasa ta  *
 *                  ma wygląd typowej fabryki, jednak jako typy zwracane przez       *
 *                  wirtualne metody fabrykujące ma zadeklarowane klasy abstrakcyjne *
 *                  reprezentujące interfejsy obiektów zwracanych przez klasy        *
 *                  pochodne. W kodzie programu implementuje się dla konkretnych     *
 *                  zastosowań klasy pochodne od fabryki abstrakcyjnej wytwarzające  *
 *                  obiekty odpowiednie dla danego systemu czy pliku                 *
 *                  konfiguracyjnego. Dzięki temu, że najczęściej fabryka jest       *
 *                  tworzona w programie tylko raz, przy zmianie zachowania obiektów *
 *                  wystarczy zmodyfikować tą linijkę w kodzie, w której następuje   *
 *                  przypisanie konkretnej fabryki.                                  *
 *                                                                                   *
 *   Przykładowy schemat (schemat opisuje inny przypadek niż kod, dla urozmaicenia): *
 *   Prezentowany jest przypadek programowania dla kilku systemów operacyjnych       *
 *                                                                                   *
 *                  Odczyt schematu:                                                 *
 *                  [Element na początku strzałki]                                   *
 *                  (d) dziedziczy po                                                *
 *                  (w) zawiera wskaźnik/wskaźniki na                                *
 *                  (t) tworzy obiekty klasy                                         *
 *                  [Element na który wskazuje strzałka]                             *
 *               _______________               ______________________                *
 *               | KlasaUsera  |-------------->|FabrykaAbstrakcyjna |                *
 *               |_____________|            (w)|____________________|                *
 *               |_____________|               |____________________|                *
 *               |_____________|               | A stworzObiekt()=0 |                *
 *                     |                       |____________________|                *
 *                     |                          /|\(d) /|\(d)  /|\(d)              *
 *                     |             ______________|      |       |________          *
 *                     |     _______|__________ __________|_______ ________|_________*
 *                     |     |FabrykaUnixowa  | |FabrykaDosowa   | |FabrykaWindows  |*
 *    -----------------/\----|________________| |________________| |________________|*
 *    |                |     |________________| |________________| |________________|*
 *    |                |     |A stworzObiekt()| |A stworzObiekt()| |A stworzObiekt()|*
 *    |                |(w)  |________________| |________________| |________________|*
 *    |    ___________\|/_____                           |                  |        *
 *    |    | A (klasa abstr) |                           |                  |        *
 *    |    |_________________|                           |                  |        *
 *    |    |_________________|                           |                  |        *
 *    |    | zareaguj()      |                           |                  |        *
 *    |    |_________________|                           |                  |        *
 *    |     /|\(d)  /|\(d)  /|\(d)                       |                  |        *
 *    |(t)___|       |       |_______                    |                  |        *
 *   \|/__|______ ___|________ _____|______              |                  |        *
 *   | AUnix    | | ADos     | | AWindows |              |                  |        *
 *   |__________| |__________| |__________|   (t)        |                  |        *
 *   |__________| |__________| |__________|<-------------/\-----------------|        *
 *   |zareaguj()| |zareaguj()| |zareaguj()|              |                           *
 *   |__________| |__________| |__________|              |                           *
 *                     /|\(t)                            |                           *
 *                      |________________________________|                           *
 *                                                                                   *
 *************************************************************************************/
 
/* Przykładowy kod. Przedstawia on rysowanie obiektów w zależności od
   szybkości procesora */
#include <iostream>//Biblioteka potrzebna w tym przykładzie
using namespace std;// dla wygody, żeby nie pisać wszędzie std
 
// Abstrakcyjny model obiektu graficznego
class ObiektGraficznyAbstrakcyjny {
   protected:   
      float x_;// położenie na ekranie w osi x
      float y_;// położenie na ekranie w osi y
   public:
         virtual void rysujSie()=0;// metoda do rysowania obiekt
         // poniższe metody są wirtualne, gdyż klasy pochodne nie muszą koniecznie w ten sposób przechowywać
         // położenia obiektu, jednak mają już ciała, gdyż to będzie najczęstszy przypadek
 
         // metoda do ustalania położenia obiektu
         virtual void ustawPozycje(float x, float y){
            x_=x;
            y_=y;         
         }
         // metody do pobierania położenia obiektu
         virtual float podajPozX() {return x_;}
         virtual float podajPozY() {return y_;}
         ObiektGraficznyAbstrakcyjny (float x, float y) : x_(x), y_(y){}
         virtual ~ObiektGraficznyAbstrakcyjny() {}//wirtualny destruktor, bo są wirtualne funkcje
};
 
// Abstrakcyjna fabryka obiektów, służąca za interfejs
class FabrykaObiektowGraficznychAbstrakcyjna {
   public:
         // metoda do tworzenia instancji obiektów
         virtual ObiektGraficznyAbstrakcyjny * utworzObiekt(float x, float y)=0;
         virtual ~FabrykaObiektowGraficznychAbstrakcyjna(){}//wirtualny destruktor, bo są wirtualne funkcje
}; 
 
// Konkretny model obiektu graficznego, dla wolniejszych komputerów
class ObiektGraficznyProsty : public ObiektGraficznyAbstrakcyjny {
   public:
         // funkcja rysujSie jest mocno okrojona, gdyż to tylko przykład zastosowania
         void rysujSie(){
            cout<<"malo wymagajacy model jest rysowany na pozycji: "<<x_<<", "<<y_<<endl;
         }
         ObiektGraficznyProsty (float x, float y):ObiektGraficznyAbstrakcyjny(x,y){}
};
 
// Konkretny model obiektu graficznego, dla szybszych komputerów
class ObiektGraficznyTrudny : public ObiektGraficznyAbstrakcyjny {
   public:
         // funkcja rysujSie jest mocno okrojona, gdyż to tylko przykład zastosowania
         void rysujSie(){
            cout<<"BARDZO WYMAGAJACY MODEL JEST RYSOWANY NA POZYCJI: "<<x_<<", "<<y_<<endl;
         }
         ObiektGraficznyTrudny (float x, float y):ObiektGraficznyAbstrakcyjny(x,y){}
};
 
//Konkretna fabryka obiektów graficznych, dla wolnych komputerów
class FabrykaObiektowGraficznychProstych : public FabrykaObiektowGraficznychAbstrakcyjna {
   public:
      // skonkretyzowanie metody
      ObiektGraficznyAbstrakcyjny * utworzObiekt(float x, float y) {
            return new ObiektGraficznyProsty(x,y);      
      }
};
 
//Konkretna fabryka obiektów graficznych, dla szybkich komputerów
class FabrykaObiektowGraficznychTrudnych : public FabrykaObiektowGraficznychAbstrakcyjna {
   public:
      // skonkretyzowanie metody
      ObiektGraficznyAbstrakcyjny * utworzObiekt(float x, float y) {
            return new ObiektGraficznyTrudny(x,y);      
      }
};
 
// Klasa korzystająca z fabryk
class KlasaUzytkowa {
   private:
      static const int ILE_OBIEKTOW=5;//ile obiektow graficznych naraz na ekranie maksymalnie
      // Wskaznik na fabryke obiektow, tu bedzie podany wskaznik do konkretnej fabryki 
      FabrykaObiektowGraficznychAbstrakcyjna * fabryka_;
      ObiektGraficznyAbstrakcyjny * pulaObiektow_[ILE_OBIEKTOW]; // Tablica obiektow do rysowania
   public:
      // dla zapełniania tablicy obiektów, zmienna nowa partia mówi czy zmieniać obiekty,
      // czy też tworzyć nowe od poczatku
      void pobierzNowe(bool nowaPartia){
         for (int licznik=0; licznik<5; ++licznik){
            ObiektGraficznyAbstrakcyjny * temp=pulaObiektow_[licznik];         
            if (temp!=NULL){// odtworzenie obiektow w nowych warunkach
                  pulaObiektow_[licznik]=fabryka_->utworzObiekt(temp->podajPozX(), temp->podajPozY());   
                  delete temp;          
            }
            else if (nowaPartia){
               pulaObiektow_[licznik]=fabryka_->utworzObiekt(licznik, ILE_OBIEKTOW - licznik);   
            }            
         }      
      }
      // dla ustawienia źródła obiektów
      void ustawFabryke(FabrykaObiektowGraficznychAbstrakcyjna * nowa_fabryka) {
            delete fabryka_;// usunięcie starej fabryki            
            fabryka_=nowa_fabryka;   // ustawienie nowej fabryki
            pobierzNowe(false);//żeby od razu zmienić typ przechowywanych obiektów   
      } 
      // dla rysowania obiektów
      void rysujObiekty(){
         for (int licznik=0; licznik<ILE_OBIEKTOW; ++licznik){
            if (pulaObiektow_[licznik]!=NULL){
                  pulaObiektow_[licznik]->rysujSie();      
            }         
         }      
      }
      // konstruktor
      KlasaUzytkowa (FabrykaObiektowGraficznychAbstrakcyjna *nowa_fabryka){
            fabryka_=nowa_fabryka;      
      }
      // destruktor
      ~KlasaUzytkowa(){
         for (int licznik=0; licznik<5; ++licznik){
            delete pulaObiektow_[licznik];// zwolnienie puli obiektów      
         }         
         delete fabryka_;// zwolnienie fabryki
      }      
};
 
//Program testowy
int main(){
      cout<<"..:: Uruchamianie programu w trybie wysokiej jakosci grafiki ::.."<<endl;
      // Na początek ustawiany bardziej wymagający typ obiektu graficznego
      KlasaUzytkowa * testowa=new KlasaUzytkowa(new FabrykaObiektowGraficznychTrudnych);
      testowa->pobierzNowe(true);// Ustawianie przykładowych obiektów
      cout<<"..:: Rysowanie przykladowych obiektow ::.."<<endl;
      testowa->rysujObiekty();
      //{...} Tutaj okazało się, że niestety maszyna jest za wolna
      cout<<"..:: Niestety maszyna jest za wolna, przelaczanie w tryb niskiej jakosci::.."<<endl;
      testowa->ustawFabryke(new FabrykaObiektowGraficznychProstych());
      cout<<"..:: Rysowanie przykladowych obiektow ::.."<<endl;
      testowa->rysujObiekty();
      cout<<"..:: Koniec programu ::.."<<endl;
}
fabryka_abstrakcyjna.txt · ostatnio zmienione: 2008/04/08 17:04 przez mchodkie