Narzędzia użytkownika

Narzędzia witryny


fabryka_prototypow

To jest stara wersja strony!


/*** * Autor: Sławomir Dybiec * Wzorzec: fabryka prototypów (rejestrowanie obiektów) * * Zastosowanie: Wzorca tego używamy, kiedy mamy informacje o typie obiektu który * chcemy utworzyć. Programista w momencie pisania kodu nie może przewidzieć, jakiej * klasy obiekt należy utworzyć. Informacja ta znana będzie dopiero podczas wykonywania * programu(np. na podstawie informacji zawartych w pliku). * * Opis: Wzorzec ten jest właściwie połączeniem wzorca fabryki obiektów oraz wzorca * prototypu. Uwaga fabryka prototypów często jest również singletonem. Zachęcam do * zapoznania się z wymienionymi przeze mnie wzorcami. * * Przykład: Załóżmy, że posiadamy klasy służące do przetwarzania plików graficznych, * jednak inna klasa odpowiada za obsługę obrazów zapisanych w formacie GIF, a innej * klasy używamy do obrazów zapisanych jako JPG. W momencie tworzenia kodu nie wiemy, * jakiego typu będzie plik który zechce przetworzyć użytkownik naszej biblioteki. * W tym momencie z pomocą przychodzi nam wzorzec fabryki prototypów. */

#include <iostream> #include <vector> #include <assert.h>

using namespace std; dla wygody, żeby nie pisać wszędzie std Typ pliku będzie reprezentowany poprzez obiekt string zawierający jego rozszerzenie typedef std::string IMG_TYPE;

Funkcja pomocnicza zwracająca nam rozszerzenie pliku. string getFileExtension(const string & filename) { string w; int a; a=filename.find_last_of(„.”); if (a==-1 || a==static_cast<int>(filename.size())-1) { Błąd plik nie posiada rozszerzenia

	assert(0);	
}
w.assign(filename, a+1, filename.size()- a-1);
//Zwracamy rozszerzenie zapisane tylko dużymi literami
std::transform(w.begin(), w.end(), w.begin(), ::toupper);
return w;

}

Klasa reprezentująca dowolny obrazek. class Image { public: Metoda zwracająca nam wskaźnik na konkretną instancje obiektu Image.

 virtual Image* Clone()=0;
 virtual string getName()=0;
 /*
  * W tym miejscu definiujemy metody obsługujące obrazek. Oczywiście są to także
  * metody wirtualne.
  */ 

}; /* * Klasa reprezentująca obrazek zapisany w formacie JPG. Jest to jednocześnie * implementacja wzorca prototyp. */ class ImageJPG : public Image {

 //Funkcja zwracająca nam wskaźnik na nowy obiekt klasy ImageJPG.
 Image* Clone() 
 {
    return new ImageJPG(*this); 
 }
 //Funkcja zwracająca srting z opisem klasy
 string getName()
 {
    return string("Klasa przetwarzająca pliki z rozszerzeniem JPG");
 }

};

Podobnie jak klasa ImageJPG. class ImageGIF : public Image { Image* Clone() { return new ImageGIF(*this); } string getName() { return string(„Klasa przetwarzająca pliki z rozszerzeniem GIF”); } }; /* * Klasa pomocnicza wiążąca prototyp klasy przetwarzającej obraz z odpowiednią wartością * pola IMG_TYPE. */ class ImagePrototype { public: ImagePrototype(IMG_TYPE t, Image *p):type(t),prototype(p){} IMG_TYPE type; Image *prototype; }; Klasa, której używamy do tworzenia obiektów. class ImagePrototypeFactory {

 std::vector<ImagePrototype> prototypes;

public:

 /*
 * Funkcja służąca do dodawania nowych prototypów klas do przetwarzania obrazów.
 * Prototypy są powiązane z odpowiednią wartością pola IMG_TYPE.
 */
 void addPrototype( IMG_TYPE img_type, Image * prototype )
 {
    ImagePrototype ip = ImagePrototype(img_type, prototype);
    prototypes.push_back( ip );
 }
 //Funkcja zwracająca wskaźnik  na obiekt, który potrafi obsługiwać zadany typ obrazka.
 Image *getImage( IMG_TYPE img_type )
 {
    int a = static_cast<int>(prototypes.size());
    for(int i=0; i < a; ++i)
       if(prototypes[i].type == img_type)
          return prototypes[i].prototype->Clone();
    //Błąd nieznany typ obrazka
    return NULL;
 }

};

int main () {

 //Tworzymy fabrykę, która będzie konstruować odpowiedni obiekt w zależności od typu pliku.
 ImagePrototypeFactory ipf;
 Image * a;
 //Dodajemy prototypy klas, potrafiących przetwarzać odpowiednie pliki.
 ipf.addPrototype("GIF", new ImageGIF());
 ipf.addPrototype("JPG", new ImageJPG());

 //Prosimy Fabrykę prototypów o wskaźnik na obiekt klasy potrafiący przetwarzać plik xxx.gif
 a = ipf.getImage(getFileExtension("xxx.gif"));
 //Prosimy klasę o przedstawienie się :)
 cout << a->getName() << endl;
 return 0;

/*
* Wyjście:
* Klasa przetwarzająca pliki z rozszerzeniem GIF
*/

}

/* * Przy własnej implementacji tego wzorca, należy pamiętać o mechanizmie obsługi wyjątków, * który tutaj został pominięty. * Innym częstym przykładem użycia tego wzorca jest zapis stanu naszego programu do pliku, * wtedy podobnie jak w wyżej wymienionym przykładzie dla każdej klasy definiujemy * odpowiedni identyfikator. Zapis każdego obiektu do pliku poprzedzony jest zapisaniem * identyfikatora klasy do której należy obiekt. Następnie przy odczycie przekazujemy ten * identyfikator do odpowiedniej funkcji fabryki prototypów(w pokazanym przeze mnie * przykładzie była to funkcja getImage()), która to funkcja zwraca nam wskazanie na nowo * utworzony obiekt klasy powiązanej z tym identyfikatorem. * Ważną cechą zaprezentowanego przeze mnie wzorca jest łatwość rozbudowy programu o dalsze klasy. * Nowo napisaną klasę(musi ona implementować wzorzec prototypu) rejestrujemy w naszej fabryce poprzez * wywołanie funkcji addPrototype. */

fabryka_prototypow.1208301801.txt.gz · ostatnio zmienione: 2008/04/16 01:23 przez sdybiec