Narzędzia użytkownika

Narzędzia witryny


fabryka_obiektow
/*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 <iostream>
#include <map>
 
/**
  * 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 Product, class Id, class ProductCreator = Product* (*)()>
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<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 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<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);
	}
}
namespace Galaxy{
	static const int ID = 2;
	class GalaxyFord : public Ford{
		public:
			virtual void Info(){
				std::cout << "Jestem Fordem Galaxy"<<std::endl;
			}
		private:
			//konkretne właściwości danego modelu
	};
	Ford* CreateGalaxyFord(){
		return new GalaxyFord;
	}
	void StartProduce(){
		FordFactory.Register(Galaxy::ID, &Galaxy::CreateGalaxyFord);
	}
	void StopProduce(){
		FordFactory.UnRegister(Galaxy::ID);
	}
}
namespace Mondeo{
	static const int ID = 3;
	class MondeoFord : public Ford{
		public:
			virtual void Info(){
				std::cout << "Jestem Fordem Mondeo"<<std::endl;
			}
		private:
			//konkretne właściwości danego modelu
	};
	Ford* CreateMondeoFord(){
		return new MondeoFord;
	}
	void StartProduce(){
		FordFactory.Register(Mondeo::ID, &Mondeo::CreateMondeoFord);
	}
	void StopProduce(){
		FordFactory.UnRegister(Mondeo::ID);
	}
}
//Przyklady użycia fabryki
int main(){
	//Trzy wskaźniki na obiekty typu Ford. Bedą się w nich znajdowały wskazania na konkretne klasy pochodne klasy Ford.
	Ford* any1; 
	Ford* any2; 
	any1 = FordFactory.CreateProduct(Focus::ID); //Próbujemy wyprodukować Forda Focus'a
	if(any1)
		any1->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"<<std::endl;
	//rejestrujemy podtyp w fabryce
	Focus::StartProduce();
	any1 = FordFactory.CreateProduct(Focus::ID);
	if(any1)
		any1->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;
	//Zaczynamy produkować modele Galaxy
	Galaxy::StartProduce();
	any2 = FordFactory.CreateProduct(Galaxy::ID); //produkujemy 1 egzemplarz Galaxy
	if(any2)
		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;
	Galaxy::StopProduce();
	Focus::StopProduce();
	//staramy sie wyprodukować Galaxy i Focus po wyrejestrowaniu ich z fabryki
	any1 = FordFactory.CreateProduct(Focus::ID);
	any2 = FordFactory.CreateProduct(Galaxy::ID);
	if(any2)
		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;
	if(any1)
		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;
	return 0;
}
fabryka_obiektow.txt · ostatnio zmienione: 2008/04/16 21:42 przez kzbikows