Narzędzia użytkownika

Narzędzia witryny


fabryka_obiektow

Różnice

Różnice między wybraną wersją a wersją aktualną.

Odnośnik do tego porównania

Both sides previous revision Previous revision
Last revision Both sides next revision
fabryka_obiektow [2008/04/16 01:28]
sdybiec usunięto
fabryka_obiektow [2008/04/16 21:41]
kzbikows utworzono
Linia 1: Linia 1:
-<code cpp> +/*Kamil Żbikowski - gr H5ISI - PRACA DOMOWA Z PRZEDMIOTU ZPR | 
-/*********************************************************************************** +|_______________________________________________________________________________| 
- *                                                            Autor: Sławomir Dybiec +| Fabryka Obiektów - rejestracja metod fabrycznych | 
- * Wzorzec: ​        ​fabryka prototypów (rejestrowanie obiektów) +| | 
-  +|Problem Tworzenie ​obiektu ​jest jezyku c++ statytyczne. Nie zawiera on | 
- * ZastosowanieWzorca tego używamy, kiedy mamy informacje o typie obiektu ​który  +| mechanizmu tworzenia obiektów w sposób dynamiczny. Pojęcia ​klasy
- * chcemy utworzyć. Programista ​momencie pisania kodu nie może przewidzieć,​ jakiej +| i obiektu są różneKlasa jest tworzona przez programistę - jest| 
- klasy obiekt należy utworzyćInformacja ta znana będzie dopiero podczas wykonywania ​ +| definicją obiektu, który to z kolei jest tworzony w trakcie | 
- programu(np. na podstawie informacji zawartych w pliku).  +| działania ​programu. Często jednak pojawia się potrzeba aby | 
- *  ​ +| w sposób dynamiczny generować obiekty ​(np. odczyt/​zapis obiektów| 
- * OpisWzorzec ten jest właściwie połączeniem wzorca ​fabryki obiektów ​oraz wzorca +| na dyskalbo nppozostawić klientom możliwość modyfikacji | 
- * prototypu. Uwaga fabryka prototypów często jest również singletonemZachęcam ​do +| zachowania obiektów za pomocą polimorfizmu poprzez wywołanie ​ | 
- * zapoznania się z wymienionymi przeze mnie wzorcami+| funkcji wirtualnej Create zdefiniowanej przez klasę wysokiego | 
-  +| poziomu. Rozwiązanie "​siłowe"​ poprzez zastosowanie instrukcji | 
- * PrzykładZałóżmyże posiadamy klasy słące do przetwarzania plików graficznych,​ +| switch nie jest najlepszym rozwiązaniem:
- * jednak inna klasa odpowiada za obsługę obrazów zapisanych w formacie GIFa innej +| - mija sie z ideą obiektowości | 
- ​* ​klasy używamy do obrazów zapisanych jako JPGW momencie tworzenia kodu nie wiemy, +| - w jednym pliku źródłowym ​jest zawarta informacja | 
- * jakiego typu będzie ​plik który zechce przetworzyć użytkownik naszej biblioteki. +|   o wszystkich podtypach co czyni go wąskim gardłem, | 
- * W tym momencie z pomocą przychodzi nam wzorzec fabryki prototypów+|   jeśli chodzi o zależności kompilacji i utrzmanie kodu.| 
-*/ +| - modyfiukując kod musimy go zmieniać w wielu miejscach | 
 +|Rozwiąznie:​ Naprzeciw powyższemu problemowi wychodzi wzorzec ​fabryki ​
 +| obiektów ​z rejestracją metod fabrycznych,​ który w przybliżeniu | 
 +| wygląda obrazuje poniższy schemat:​ | 
 +| _______ _______________________ |  
 +| |Produkt|<​--------------| ​    ​FabrykaObiektow | | 
 +| |_______| |-----------------------| | 
 +|     ^ |+ StworzProdukt() | | 
 +|     | |+ RejestrujProduct() | | 
 +|     | |_______________________| | 
 +| ___|_____ | 
 +| |Produkt ​ | |  
 +| |Konkretny| | 
 +| |_________| | 
 +| | 
 +| Produkt konkretny - fabryka dostarcza produkt w postaci obiektu | 
 +| Produkt - abstrakcyjny typ podstawowyFabryka zwraca wskaźnik | 
 +|   ​do tego obiektu nie przekazując informacji o produkcie| 
 +|   konkretnym. | 
 +| Informacje o konkretnym produkcie przechowywane są przez fabrykę| 
 +| w mapie (np. std::map). Każdy konkretny produkt ma przydzielony | 
 +| unikalny identyfiaktor na podstawiektórego jest identyfikowany| 
 +| Własciwie jest przechowywany wskaźnik do funkcji zwracającej | 
 +| wskaźnik ​do Produkt. | 
 +| Rejestracja kolejnego produktu konkretnego odbywa się poprzez | 
 +| podanie unikalnego identyfikatora danego Produktu Konkretnego | 
 +| oraz wskaźnika na funkcję zwracającą wskaźnik na Produkt. | 
 +| Dzięki zastosowaniu polimorfizmu wyeliminowaliśmy wady | 
 +| rozwiązania siłowego. Teraz dodanie kolejnego Produktu | 
 +| Konkretnego sprowadza się do stworzenia nowej klasy definiującej| 
 +| gozawierającej metodę postaci:​ | 
 +| ProduktStworzKonkretnyProdukt(){ | 
 +| return new ProduktKonkretny;​ | 
 +| } | 
 +| Rejestracja natomiast polega na wywolaniu RegisterProduct na | 
 +| rzecz wyżej wymienionej metodyOd tej chwili stworzenie | 
 +| konkretnego produktu ​będzie ​polegało na wywołaniu metody | 
 +| StworzProdukt z okrślonym id podanym w porcesie rejstracji | 
 +| Czesto fabryka obiektów powinna być singletonem,​ ale to juz jest| 
 +| temat na oddzielną pracę
 +|______________________________________________________________________________*/
 #include <​iostream>​ #include <​iostream>​
-#include <vector>​ +#include <map>
-#include <​assert.h>+
  
-using namespace std;// dla wygodyżeby nie pisać wszędzie std +/** 
- +  * Szablon fabryki. Product - klasa abstrakcyjanId - identyfiaktor klasy, ProductCreator -  
-//Typ pliku będzie reprezentowany poprzez ​obiekt ​string zawierający jego rozszerzenie ​ +  * wskaźnik na funkcję zwracającą wskaźnik na obiekt ​konkretny dziedziczący po Product 
-typedef std::string IMG_TYPE; +  */ 
- +template <class Product, class Id, class ProductCreator = Product* (*)()> 
-//Funkcja pomocnicza zwracająca nam rozszerzenie pliku.  +class Factory{ 
-string getFileExtension(const ​string ​filename+ public: 
-+ //Metoda produkująca konkretne obiekty na podstawie ich identyfiaktorów
- string w+ Product* CreateProduct(const ​Idid){ 
- int a+ typename Map::​const_iterator i = associations.find(id);​ 
- a=filename.find_last_of("."); + if(i != associations.end())
- if (a==-|| a==static_cast<int>​(filename.size())-1) + return (i->​second()) //​jeśli w mapie jest podany w parametrze klucz 
-+        //​wywołaj powiązaną z nim funkcję 
- //Błąd plik nie posiada rozszerzenia +
- assert(0); + else 
 + return NULL//obsługa błędów - przykładowe rozwiązanie 
 +      //​można zaimplementować rozwiązanie z użyciem wyjątków 
 +
 + //Metoda rejestrująca obiekty w fabryce. 
 + bool Register(const Id& id, ProductCreator creator){ 
 + return associations.insert( 
 + typename Map::​value_type(id,​ creator)).second
 +
 + //Metoda wyrejestrowująca obiekty. 
 + bool UnRegister(const Id& id){ 
 + return associations.erase(id) ​== 1
 +
 + private: 
 + typedef std::​map<​Id,​ ProductCreator>​ Map;  
 + Map associations;​ //mapa służy do połączenia identyfiatora z danym wskźnikiem na funkcję 
 +   //wymagane jest aby Id miało zaimplementowane operatory '==', '<
 +   // 
 +}; 
 +//Klasa abstrakcyjna FordDiedziczą po niej konkretne modele samochodów,​ które rejestrują się w fabryce 
 +//a następnie są przez nią produkowane. 
 +class Ford{ 
 + public: 
 + //​funkcja,​ która w każdej z klas dziedziczących po Ford  
 + //​wyświetla rodzaj danego obiektu 
 + virtual void Info() = 0; 
 +}; 
 +Factory<​Ford,​ int> FordFactory;​ //obiekt relizujący fabrykę samochodów marki Ford 
 +//Każda z poniższych przestrzeni nazw zawierająca konkretne implementacje  
 +//klasy Ford może znajdować się w osobnym pliku. Chcąc dodać kolejną markę samochodu 
 +//dodajemy kolejny plik z zawartością podobną jak każdy z namespace'​ow.  
 +namespace Focus{ 
 + static const int ID = 1; 
 + class FocusFord : public Ford
 + public: 
 + virtual void Info(){ 
 + std::​cout << "​Jestem Fordem Focus"<<​std::​endl;​ 
 +
 + private:​ 
 + //konkretne właściwości danego modelu 
 + }; 
 + Ford* CreateFocusFord(){ 
 + return new FocusFord;​ 
 +
 + void StartProduce(){ 
 + FordFactory.Register(Focus::​ID,​ &​Focus::​CreateFocusFord);​ 
 +
 + void StopProduce(){ 
 + FordFactory.UnRegister(Focus::​ID);
  }  }
- 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; 
 } }
- +namespace Galaxy{ 
-//Klasa reprezentująca dowolny obrazek. + static const int ID = 2; 
-class Image  + class ​GalaxyFord : public Ford
-+ public: 
-public: + virtual ​void Info(){ 
-   //Metoda zwracająca nam wskaźnik na konkretną instancje obiektu Image. + std::​cout << "​Jestem Fordem Galaxy"<<​std::​endl
-   virtual ​Image* Clone()=0; + } 
-   virtual string getName()=0+ private: 
-   /* + //konkretne ​właściwości danego modelu 
-    * W tym miejscu definiujemy metody obsługujące obrazek. Oczywiście są to także + }; 
-    * metody wirtualne. + FordCreateGalaxyFord()
-    * + return new GalaxyFord; 
-}; +
-/+ void StartProduce(){ 
-* Klasa reprezentująca obrazek zapisany ​formacie JPG. Jest to jednocześnie + FordFactory.Register(Galaxy::ID, &​Galaxy::​CreateGalaxyFord); 
-* implementacja wzorca prototyp. +
-*+ void StopProduce(){ 
-class ImageJPG : public Image + FordFactory.UnRegister(Galaxy::ID); 
-   //Funkcja zwracająca nam wskaźnik na nowy obiekt klasy ImageJPG. +
-   Image* Clone()  +
-   +namespace Mondeo{ 
-      ​return new ImageJPG(*this);  + static const int ID = 3; 
-   ​+ class ​MondeoFord ​: public ​Ford
-   //Funkcja zwracająca srting z opisem klasy + public: 
-   ​string getName() + virtual void Info(){ 
-   + std::​cout << ​"Jestem Fordem Mondeo"<<​std::​endl
-      ​return string("Klasa przetwarzająca pliki z rozszerzeniem JPG"); +
-   ​+ private: 
-}; + //konkretne właściwości danego modelu 
- + }; 
-//Podobnie jak klasa ImageJPG. + FordCreateMondeoFord(){ 
-class ImageGIF ​: public ​Image + return new MondeoFord; 
-   Image* Clone() ​ +
-   { + void StartProduce()
-      return new ImageGIF(*this);  + FordFactory.Register(Mondeo::ID&Mondeo::​CreateMondeoFord)
-   } +
-   ​string getName() + void StopProduce(){ 
-   + FordFactory.UnRegister(Mondeo::​ID)
-      ​return string("Klasa przetwarzająca pliki z rozszerzeniem GIF")+ } 
-   ​+
-}; +//Przyklady ​ycia fabryki 
-/+int main()
-* Klasa pomocnicza wiążąca prototyp klasy przetwarzającej obraz z odpowiednią wartością + //Trzy wskaźniki na obiekty typu FordBedą się w nich znajdowały wskazania na konkretne klasy pochodne klasy Ford
-* pola IMG_TYPE. + Fordany1;  
-*/ + Fordany2;  
-class ImagePrototype + any1 FordFactory.CreateProduct(Focus::ID); //​Próbujemy wyprodukować Forda Focus'​a 
-+ if(any1) 
-public: + any1->​Info(); //jeśli się udało to wyświetl informacje o samochodzie 
-   ​ImagePrototype(IMG_TYPE tImage *p):type(t),prototype(p){} + //oczywiście w tym wypadku operacja się nie udaponieważ nie  
-   IMG_TYPE type+ //​zarejestrowaliśmy tego podtypu w fabryce 
-   Image *prototype; + else 
-}; + //jeśli nie to wypisz stosowny komunikat 
-//Klasa, której ​ywamy do tworzenia obiektów. + std::cout<<"​Fabryka nie produkuje tego typu samochodu"<<​std::​endl;​ 
-class ImagePrototypeFactory + //​rejestrujemy podtyp w fabryce 
-{  + Focus::​StartProduce(); 
-   std::​vector<​ImagePrototype>​ prototypes;​ + any1 FordFactory.CreateProduct(Focus::​ID); 
-public: + if(any1
-   /+ any1->Info(); //jeśli się udało to wyświetl informacje o samochodzie,​ teraz już dokonaliśmy rejestracji 
-   * Funkcja służąca do dodawania nowych prototypów klas do przetwarzania obrazów. + else 
-   * Prototypy są powiązane z odpowiednią wartością pola IMG_TYPE+ //jeśli nie to wypisz stosowny komunikat 
-   ​*/ + std::​cout<<"​Fabryka nie produkuje tego typu samochodu"<<​std::​endl
-   void addPrototype( IMG_TYPE img_type, Image prototype ) + //Zaczynamy produkować modele Galaxy 
-   { + Galaxy::​StartProduce()
-      ImagePrototype ip ImagePrototype(img_type, prototype); + any2 = FordFactory.CreateProduct(Galaxy::​ID);​ //​produkujemy 1 egzemplarz Galaxy 
-      ​prototypes.push_backip ); + if(any2
-   } + any2->​Info();​ //jeśli się udało to wyświetl informacje o samochodzieteraz już dokonaliśmy rejestracji 
-   //Funkcja zwracająca wskaźnik ​ na obiektktóry potrafi obsługiwać zadany typ obrazka. + else 
-   Image *getImage( IMG_TYPE img_type ) + //jeśli nie to wypisz stosowny komunikat 
-   { + std::​cout<<​"Fabryka nie produkuje tego typu samochodu"<<​std::​endl;​ 
-      int a = static_cast<int>​(prototypes.size()); + Galaxy::​StopProduce(); 
-      ​for(int i=0; i < a; ++i+ Focus::​StopProduce(); 
-         ​if(prototypes[i].type == img_type+ //staramy sie wyprodukować Galaxy i Focus po wyrejestrowaniu ich z fabryki 
-            ​return prototypes[i].prototype->Clone(); + any1 = FordFactory.CreateProduct(Focus::​ID);​ 
- + any2 FordFactory.CreateProduct(Galaxy::​ID);​ 
-      //Błąd nieznany typ obrazka + if(any2) 
-      ​return NULL+ any2->​Info(); //jeśli ​się udało to wyświetl informacje o samochodzie,​ teraz już dokonaliśmy rejestracji 
-   } + else 
-}+ //jeśli nie to wypisz stosowny komunikat 
- + std::cout<<​"​Fabryka nie produkuje tego typu samochodu"​<<std::endl; 
-int main () + if(any1) 
-{  + any2->​Info(); //jeśli się udało to wyświetl informacje o samochodzie,​ teraz już dokonaliśmy rejestracji 
-   //Tworzymy fabrykę, która będzie konstruować odpowiedni obiekt w zależności od typu pliku. + else 
-   ImagePrototypeFactory ipf; + //jeśli nie to wypisz stosowny komunikat 
-   Image * a; + std::​cout<<"​Fabryka nie produkuje tego typu samochodu"<<​std::​endl;​ 
-   //Dodajemy prototypy klas, potrafiących przetwarzać odpowiednie pliki. + return 0;
-   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. 
- */ 
- </​code>​ 
fabryka_obiektow.txt · ostatnio zmienione: 2008/04/16 21:42 przez kzbikows