/*Kamil Żbikowski - gr H5ISI - PRACA DOMOWA Z PRZEDMIOTU ZPR | |_______________________________________________________________________________| | Fabryka Obiektów - rejestracja metod fabrycznych | | | |Problem: Tworzenie obiektu jest w jezyku c++ statytyczne. Nie zawiera on | | mechanizmu tworzenia obiektów w sposób dynamiczny. Pojęcia klasy| | i obiektu są różne. Klasa jest tworzona przez programistę - jest| | definicją obiektu, który to z kolei jest tworzony w trakcie | | działania programu. Często jednak pojawia się potrzeba aby | | w sposób dynamiczny generować obiekty (np. odczyt/zapis obiektów| | na dysk) albo np. pozostawić klientom możliwość modyfikacji | | zachowania obiektów za pomocą polimorfizmu poprzez wywołanie | | funkcji wirtualnej Create zdefiniowanej przez klasę wysokiego | | poziomu. Rozwiązanie "siłowe" poprzez zastosowanie instrukcji | | switch nie jest najlepszym rozwiązaniem: | | - mija sie z ideą obiektowości | | - w jednym pliku źródłowym jest zawarta informacja | | o wszystkich podtypach co czyni go wąskim gardłem, | | 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 podstawowy. Fabryka 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 podstawie, któ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| | go, zawierającej metodę postaci: | | Produkt* StworzKonkretnyProdukt(){ | | return new ProduktKonkretny; | | } | | Rejestracja natomiast polega na wywolaniu RegisterProduct na | | rzecz wyżej wymienionej metody. Od 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 #include /** * Szablon fabryki. Product - klasa abstrakcyjan, Id - identyfiaktor klasy, ProductCreator - * wskaźnik na funkcję zwracającą wskaźnik na obiekt konkretny dziedziczący po Product */ template class Factory{ public: //Metoda produkująca konkretne obiekty na podstawie ich identyfiaktorów. Product* CreateProduct(const Id& id){ typename Map::const_iterator i = associations.find(id); if(i != associations.end()){ return (i->second()); //jeśli w mapie jest podany w parametrze klucz //wywołaj powiązaną z nim funkcję } 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 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 Ford. Diedziczą 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 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"<Info(); //jeśli się udało to wyświetl informacje o samochodzie //oczywiście w tym wypadku operacja się nie uda, ponieważ nie //zarejestrowaliśmy tego podtypu w fabryce else //jeśli nie to wypisz stosowny komunikat std::cout<<"Fabryka nie produkuje tego typu samochodu"<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"<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"<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"<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"<