Narzędzia użytkownika

Narzędzia witryny


prototyp

Prototyp (wzorzec projektowy)

Wzorzec prototypu umożliwia łatwe kopiowanie obiektów do których z przyczyn wygody lub konieczności (np. przechowywania ich w jednym kontenerze) posiadamy jedynie wskaźniki na klasę bazową. Dzięki wykorzystywanej we wzorcu wirtualnej funkcji klonuj() nie ma potrzeby sprawdzania na jakiej klasy obiekt wskazuje w danej chwili wskaźnik klasy bazowej. Nie musimy też martwić się o tzw. wycinanie, czyli kopiowanie jedynie części obiektu (tej należącej do klasy bazowej).

Wzorzec prototypu wykorzystywany jest także w przypadku tworzenia obiektów, w których bardzo skomplikowany jest proces inicjowania obiektu (np. jeśli konieczne jest wiele zapytań do bazy danych). Programista może stworzyć wtedy jeden prototyp, a następnie wielokrotnie klonować gotowy już obiekt z ewentualnym wprowadzaniem małych zmian jego składowych.

Idea działania wzorca

Klient wykorzystuje jedynie klasę bazową (np. posługując się wskaźnikami na klasę bazową). W rzeczywistości może być to zupełnie abstrakcyjna klasa, która musi posiadać (czysto) wirtualną metodę void klonuj(). Jest ona natomiast implementowana we wszystkich klasach dziedziczących, które reprezentują konkretne obiekty. Tam ma ona możliwość stworzenia poprawnego obiektu.

Zaleca się też ustawienie konstruktora kopiującego klasy bazowej jako prywatnego, dzięki czemu użytkownik nawet przez przypadek nie będzie mógł go źle użyć. Co najczęściej wiązałoby się z efektem wycinania.

Przykładowy kod

Przykładowy kod w języku C++ wraz z programem ilustrującym użycie.
Plik z kodem można można znaleźć też tu: prototyp.cpp

#include <vector>
 
/*
 * Klasa bazowa implementujaca interfejs prototypu.
 * Ta klasa posluguje sie uzytkownik, operujac na
 * konkretnych obiektach klas z niej dziedziczacych,
 * ktorch nazw nie musi czesto nawet znac.
 */
class Multimedia{
public:
	/* 
	 * deklaracja czysto wirtualnej funkcji klonuj(),
	 * ktora musi zostac zdefiniowana we wszystkich
	 * klasach dziedziczacych.
	 */
	virtual Multimedia* klonuj() = 0;
	Multimedia(){/* */}
private:
	/*
	 * Prywatny kondtruktor kopiujacy klasy bazowej
	 * pozwala uniknšc najprawdopodobniej blednego
	 * (poniewaz obiekty klasy bazowej nie powinny byc
	 * tworzone) kopiowania obiektow.
	 */
	Multimedia(const Multimedia& );
	/*
	 * Dalsza definicja klasy pominieta dla zachowania
	 * czytelnosci przykladu prototypu
	 */
};
 
/*
 * Przyklad klasy dziedziczacej z klasy Multimedia, 
 * reprezentujacej konkretne obiekty wykorzystywane 
 * przez uzytkownika. Musi ona implementowac fukncje 
 * klonuj().
 */
class Obraz: public Multimedia {
public:
	Obraz(){/* */}
	/*
	 * Obowiazkowo zdefiniowana funckja klonuj() moze 
	 * wykonac poprawne skopiowanie obektu bez obawy 
	 * o wycinanie.
	 */
	virtual Obraz* klonuj() {
		return new Obraz(*this);
	}
	/*
	 * Konstruktor kopiujacy moze byc juz publiczny 
	 * gdy sa to juz klasy reprezentujace rzeczywiste 
	 * obiekty wykorzystywane przez uzytkownika i sa 
	 * one liscmi w drzewie hierarchi klas wiec nie 
	 * musimy obawiac sie wycinania przy kopiowaniu.
	 */
	Obraz(const Obraz& ){};
};
 
/*
 * Przyklad klasy dziedziczacej z Multimedia.
 * Patrz: opis klasy Obraz.
 */
class Muzyka: public Multimedia {
public:
	Muzyka(){/* */}
	virtual Muzyka* klonuj() {
		return new Muzyka(*this);
	}
	Muzyka(const Muzyka& ){};
};
 
/*
 * Przyklad klasy dziedziczacej z Multimedia.
 * Patrz: opis klasy Obraz.
 */
class Film: public Multimedia {
public:
	Film(){/* */}
	virtual Film* klonuj() {
		return new Film(*this);
	}
	Film(const Film& ){};
};
 
 
/*******************************************
 * Przykład wykorzystania wzorca prototyp. *
 *******************************************/
int main(){
	std::vector<Multimedia*> katalog;
	katalog.push_back(new Obraz);
	katalog.push_back(new Muzyka);
	katalog.push_back(new Film);
	/*
	 * W wektorze katalog znajduja sie wskazniki
	 * do 3 obiektow klas dziedziczacych z klasy
	 * Multimedia, lecz sa to wskazniki na obiekty
	 * klasy bazowej.
	 */
 
	std::vector<Multimedia*> plytka_kopia_katalogu = katalog;
	/*
	 * Tak wykonana kopia katalogu zawieralaby 
	 * jedynie wskazniki na te same obiekty, a 
	 * zapewne nie o to nam chodzi, jesli ma byc
	 * to na przyklad kopia dla innego uzytkowniki 
	 * lub kopia zapasowa.
	 */
 
	std::vector<Multimedia*> kopia_katalogu;
	for(std::vector<Multimedia*>::iterator it = katalog.begin(); it != katalog.end(); ++it){
		kopia_katalogu.push_back( (*it)->klonuj() );
	}
	/*
	 * Dopiero tak wykonana kopia dzieki wykorzystaniu
	 * wirtualnej funkcji klonuj() wykona poprawna kopie 
	 * wszystkich obiektow. Jest to jeden z przykladow
	 * zastosowania wzorca prototypu.
	 */
 
	return 0;
}
prototyp.txt · ostatnio zmienione: 2008/04/16 23:15 przez jwawer