Narzędzia użytkownika

Narzędzia witryny


fabryka_obiektow

To jest stara wersja strony!


/*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

#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.1208374899.txt.gz · ostatnio zmienione: 2008/04/16 21:41 przez kzbikows