Wzorce kreacyjne Flashcards
Wzorce kreacyjne
• budowniczy • fabryki -> prosta fabryka* -> metoda wytwórcza -> fabryka abstrakcyjna • prototyp • singleton
Budowniczy - nazwa
ang. builder
Budowniczy - kategoria
obiektowy, konstrukcyjny
Budowniczy - Przeznaczenie
Oddzielenie tworzenia złożonego obiektu od jego reprezentacji, dzięki czemu proces konstrukcji może prowadzić do powstawania różnych reprezentacji.
Budowniczy - Uzasadnienie
Edytory dokumentów tekstowych powinny obsługiwać wiele formatów plików.
Liczba możliwości jest nie do określenia, powinna być możliwość dodania obsługi nowych rozszerzeń.
Budowniczy - Warunki stosowania
• gdy istnieje potrzeba zbudowania złożonego obiektu (tzw. kompozytu)
-> NIE TWORZYĆ super klasy, łamie SOLID!
• jeśli algorytm tworzenia obiektu złożonego powinien być niezależny od składników tego obiektu i sposobu ich łączenia;
• kiedy proces konstrukcji musi umożliwiać tworzenie różnych reprezentacji generowanego obiektu;
Budowniczy - Elementy
• Budowniczy (Builder):
- określa interfejs abstrakcyjny do tworzenia składników obiektu Product.
• KonkretnyBudowniczy (ConcreteBuilder):
- tworzy i łączy składniki produktu w implementacji interfejsu klasy Budowniczy;
- definiuje i śledzi generowane reprezentacje;
- udostępnia interfejs do pobierania produktów.
• Kierownik (Director):
- tworzy obiekt za pomocą interfejsu klasy Budowniczy.
• Produkt (Product):
- reprezentuje generowany obiekt złożony; klasa KonkretnyBudowniczy tworzy wewnętrzną reprezentację produktu i definiuje proces jej składania;
- obejmuje klasy definiujące składowe elementy obiektu, w tym inte`rfejsy do łączenia składowych w ostateczną postać obiektu.
Budowniczy - Współdziałanie
- Klient tworzy Kierownika i konfiguruje go za pomocą odpowiedniego obiektu Budowniczy;
- w celu utworzenia części produktu, obiekt Kierownik wysyła powiadomienie do obiektu Budowniczy;
- obiekt Budowniczy obsługuje żądania obiektu Kierownik i dodaje części produktu;
- Klient pobiera produkt od obiektu Budowniczy.
Budowniczy - Konsekwencje
- Możliwość zróżnicowania wewnętrznych struktur klas. Do produkcji służy interfejs abstrakcyjny, jego zmiana wymaga jedynie zdefiniowania obiektu Budowniczy nowego rodzaju.
- Duża skalowalność - dodawanie nowych reprezentacji obiektów jest uproszczone.
- Odizolowanie reprezentacji wewnętrznej od kodu tworzenia produktu (proces produkcyjny niezależny od elementów z których składa się obiekt).
- Każdy obiekt KonkretnyBudowniczy zawiera cały kod potrzebny do tworzenia i składania produktów odkreślonego rodzaju.
- Większa kontrola nad procesem tworzenia. Generowanie krok po kroku pod kontrolą Kierownika. Dopiero na koniec Kierownik odbiera od Budowniczego gotowy obiekt.
- Nieumiejętne używanie wzorca może spowodować nieczytelność kodu (jeden produkt może być tworzony przez zbyt wielu budowniczych).
Budowniczy - Implementacja
Zwykle w implementacji znajduje się klasa abstrakcyjna Budowniczy obejmująca definicję operacji dla każdego komponentu, którego utworzenia może zażądać obiekt Kierownik. Domyślnie operacje te nie wykonują żadnych działań. W klasie KonkretnyBudowniczy przesłonięte są operacje komponentów, które klasa ta ma generować
Prosta Fabryka - nazwa
ang. simple factory
antywzorzec(?)
Prosta fabryka - Przeznaczenie
Często stosuje się prostą fabrykę, gdy chcemy wyodrębnić fragment odpowiedzialny za utworzenie konkretnego produktu do osobnej klasy
Prosta Fabryka - Struktura
- może być statyczna,
- będzie tylko jedna,
- podajemy jej typ obiektu, który ma stworzyć, a ona w środku ma switch case, które tworzą konkretne obiekty
Jako że łamie trochę SOLIDa często uważana za antywzorzec → kiedy chcemy dodać przypadek w wielu miejscach musimy robić zmiany (enum, switch case, klasa obiektu)
Metoda wytwórcza - nazwy
ang. factory method
pol. konstruktor wirtualny
ang. virtual constructor
Metoda wytwórcza - kategoria
klasowy,
konstrukcyjny
Metoda wytwórcza - Przeznaczenie
Określa interfejs do tworzenia obiektów, przy czym umożliwia podklasom wyznaczenie klasy danego obiektu. Metoda wytwórcza umożliwia klasom przekazanie procesu tworzenia egzemplarzy podklasom.
Metoda wytwórcza - Uzasadnienie
- W systemach/programach klasy abstrakcyjne służą do definiowania i podtrzymywania relacji między obiektami.
- Ponieważ określona podklasa klasy Document, której egzemplarz należy utworzyć, jest specyficzna dla aplikacji, w klasie Application nie można z góry ustalić rodzaju tej podklasy. Klasa Application potrafi jedynie określić, kiedy należy utworzyć nowy dokument, a nie jakiego rodzaju powinien on być. Stawia nas to przed dylematem — platforma musi tworzyć egzemplarze klas, ale ma informacje tylko o klasach abstrakcyjnych, których egzemplarzy wygenerować nie może.
- Rozwiązaniem jest zastosowanie wzorca Metoda wytwórcza. Pozwala on zakapsułkować informacje o tym, którą podklasę klasy Document należy utworzyć i zapisać te dane poza platformą.
Metoda wytwórcza - Warunki stosowania
- Kiedy w danej klasie nie można z góry ustalić klasy obiektów, które trzeba utworzyć.
- Jeśli programista chce, aby to podklasy danej klasy określały tworzone przez nią obiekty.
- Jeżeli klasy delegują zadania do jednej z kilku podklas pomocniczych, a programista chce zapisać w określonym miejscu informacje o tym, która z tych podklas jest delegatem.
Metoda wytwórcza - Elementy
• Produkt (Product):
- definiuje interfejs obiektów generowanych przez metodę wytwórczą.
• KonkretnyProdukt (ConcreteProduct):
- obejmuje implementację interfejsu klasy Produkt.
• Wytwórca (Creator):
- obejmuje deklarację metody wytwórczej zwracającej obiekty typu Produkt;
- w obiekcie Wytwórca można też zdefiniować implementację domyślną metody fabrycznej, zwracającą domyślny obiekt KonkretnyProdukt;
- może wywoływać metodę wytwórczą [np. stwórz()] w celu wygenerowania obiektu Produkt.
• KonkretnyWytwórca (ConcreteCreator):
- przesłania metodę wytwórczą, tak aby zwracała egzemplarz klasy KonkretnyProdukt.
Metoda wytwórcza - Współdziałanie
Klasa Kreator działa na podstawie założenia, że w jej podklasach zdefiniowana jest metoda wytwórcza zwracająca egzemplarz odpowiedniej klasy KonkretnyProdukt.
Metoda wytwórcza - Konsekwencje
Metoda wytwórcza eliminuje konieczność wiązania klas specyficznych dla aplikacji z kodem, W kodzie używany jest tylko interfejs klasy Product, dlatego działać w nim będzie dowolna zdefiniowana przez użytkownika klasa ConcreteProduct.
• Zapewnienie punktów zaczepienia dla podklas
• Połączenie równoległych hierarchii klas.
• Niezależność od konkretnych implementacji zasobów oraz procesu ich tworzenia.
• Wzorzec hermetyzuje proces tworzenia obiektów, zamykając go za ściśle zdefiniowanym interfejsem.
• Spójność produktów – w sytuacji, gdy pożądane jest, aby produkty były z określonej rodziny
Metoda wytwórcza - Implementacja - Odmiany
- utworzenie klasy Kreator jako klasy abstrakcyjnej i pominięcie w niej implementacji zadeklarowanej metody wytwórczej
- utworzenie klasy Kreator jako klasy konkretnej i umieszczenie w niej domyślnej implementacji metody wytwórczej. Można też utworzyć klasę abstrakcyjną z definicją implementacji domyślnej, jednak jest to rzadziej stosowane rozwiązanie.
- Sparametryzowane metody wytwórcze.
Utworzenie klasy Kreator jako klasy abstrakcyjnej i pominięcie w niej implementacji zadeklarowanej metody wytwórczej
w podklasie trzeba zdefiniować implementację, ponieważ nie istnieje przydatna implementacja domyślna. Pozwala to rozwiązać problem tworzenia egzemplarzy nieprzewidzianych klas.
Utworzenie klasy Kreator jako klasy konkretnej i umieszczenie w niej domyślnej implementacji metody wytwórczej
umieszczenie metody wytwórczej w konkretnej klasie Kreator służy przede wszystkim zwiększeniu elastyczności. Podejście to jest zgodne z następującą zasadą: „Twórz obiekty za pomocą odrębnej operacji, aby można przesłonić sposób ich generowania podklasach”. Ta reguła gwarantuje, że projektanci podklas będą mogli w razie potrzeby zmienić klasę obiektów generowanych przez klasę nadrzędną.
Sparametryzowane metody wytwórcze
Inna odmiana wzorca umożliwia metodom wytwórczym generowanie produktów wielu rodzajów. Metoda wytwórcza przyjmuje wtedy parametr określający rodzaj generowanego obiektu. Wszystkie obiekty tworzone przez taką metodę wytwórczą będą miały wspólny interfejs klasy Product.
Fabryka abstrakcyjna
ang. abstract factory
pol. zestaw
ang. kit
Fabryka abstrakcyjna - kategoria
obiektowy,
konstrukcyjny
Fabryka abstrakcyjna - Przeznaczenie
Udostępnia interfejs do tworzenia rodzin powiązanych ze sobą lub zależnych od siebie obiektów bez określania ich klas konkretnych.
Fabryka abstrakcyjna - Uzasadnienie
Aplikacja generująca plik w zależności od używanej platformy/obsługiwanych technologii – html/pdf, html5/flash
Fabryka abstrakcyjna - Warunki stosowania
- Kiedy system powinien być niezależny od sposobu tworzenia, składania i reprezentowania jego produktów.
- Jeśli system należy skonfigurować za pomocą jednej z wielu rodzin produktów.
- Jeżeli powiązane obiekty-produkty z jednej rodziny są zaprojektowane do wspólnego użytku i trzeba wymusić jednoczesne korzystanie z tych obiektów.
- Kiedy programista chce udostępnić klasę biblioteczną produktów i ujawnić jedynie ich interfejsy, a nie implementacje.
Fabryka abstrakcyjna - Elementy i współdziałanie
• FabrykaAbstrakcyjna (AbstractFactory):
- obejmuje deklarację interfejsu z operacjami tworzącymi produkty abstrakcyjne.
• KonkretnaFabryka (ConcreteFactory):
- obejmuje implementację operacji tworzących produkty konkretne.
• ProduktAbstrakcyjny (AbstractProduct):
- obejmuje deklarację interfejs dla produktów określonego typu.
• ProduktKonkretny (ConcreteProduct):
- definiuje obiekt-produkt tworzony przez odpowiadającą mu fabrykę konkretną;
- obejmuje implementację interfejsu klasy ProduktAbstrakcyjny.
• Klient (Client):
- korzysta jedynie z interfejsów zadeklarowanych w klasach FabrykaAbstrakcyjna i ProduktAbstrakcyjny
Fabryka abstrakcyjna - Elementy i współdziałanie
- W czasie wykonywania programu powstaje zwykle jeden egzemplarz klasy KonkretnaFabryka. Ta fabryka tworzy obiekty-produkty o określonej implementacji. Aby wygenerować różne obiekty-produkty, Klienty muszą użyć odmiennych Fabryk Konkretnych.
- Klasa FabrykaAbstrakcyjna przekazuje tworzenie obiektów-produktów do swojej podklasy KonkretnaFabryka.
Fabryka abstrakcyjna - Konsekwencje
- Izoluje klasy konkretne.
- Ułatwia zastępowanie rodzin produktów.
- Ułatwia zachowanie spójności między produktami.
- Utrudnia dodawanie obsługi produktów nowego rodzaju.
Fabryka abstrakcyjna - Implementacja
- Fabryki jako singletony. W aplikacji zwykle potrzebny jest tylko jeden egzemplarz klasy KonkretnaFabryka na każdą rodzinę produktów.
- Tworzenie produktów. Klasa FabrykaAbstrakcyjna obejmuje jedynie deklarację interfejsu do tworzenia produktów. To podklasy ProduktKonkretny odpowiadają za ich generowanie. Choć taka implementacja jest prosta, wymaga przygotowania dla każdej rodziny produktów nowej podklasy konkretnej reprezentującej fabrykę, nawet jeśli różnice między poszczególnymi rodzinami są niewielkie.
- Definiowanie rozszerzalnych fabryk. W klasie FabrykaAbstrakcyjna zwykle zdefiniowane są różne operacje dla wszystkich rodzajów produktów generowanych przez tę klasę. Dodanie produktu nowego rodzaju wymaga zmodyfikowania interfejsu klasy FabrykaAbstrakcyjna i wszystkich klas od niego zależnych.
Prototyp - nazwy
ang. prototype
Prototyp - kategorie
obiektowy, konstrukcyjny
Prototyp - Przeznaczenie
Określa na podstawie prototypowego egzemplarza rodzaje tworzonych obiektów i generuje nowe
obiekty przez kopiowanie tego prototypu.
Prototyp - Uzasadnienie
Można zbudować edytor partytur przez dostosowanie ogólnej platformy do tworzenia edytorów graficznych i dodanie nowych obiektów reprezentujących nuty, pauzy i pięciolinie. Platforma do tworzenia edytorów może udostępniać paletę narzędzi do dodawania takich obiektów muzycznych do partytury. W palecie mogą znaleźć się też narzędzia do zaznaczania i przenoszenia tych obiektów oraz manipulowania nimi.
Prototyp - Warunki stosowania
- klasy tworzonych egzemplarzy są określane w czasie wykonywania programu (na przykład przez dynamiczne wczytywanie)
- programista chce uniknąć tworzenia hierarchii klas fabryk odpowiadającej hierarchii klas produktów
- egzemplarze klasy mogą przyjmować jeden z niewielu stanów; wygodniejsze może wtedy okazać się dodanie odpowiedniej liczby prototypów i klonowanie ich zamiast ręcznego tworzenia egzemplarzy klasy (za każdym razem z właściwym stanem).
Prototyp - Elementy
• Prototyp (Prototype):
- obejmuje deklarację interfejsu do klonowania.
• KonkretnyPrototyp (ConcretePrototype):
- obejmuje implementację procesu klonowania.
• Klient (Client):
- tworzy nowy obiekt przez zażądanie od prototypu sklonowania się.
Prototyp - Współdziałanie
Klient żąda od prototypu, aby ten się sklonował.
Prototyp - Konsekwencje
- Możliwość dodawania i usuwania produktów w czasie wykonywania programu.
- Możliwość określania nowych obiektów przez zmianę wartości.
- Możliwość określania nowych obiektów przez modyfikowanie struktury
- Zmniejszenie liczby podklas.
- Możliwość dynamicznego konfigurowalna aplikacji za pomocą klas
- Wzorzec Prototyp można stosować w sytuacjach, gdy tworzona jest duża liczba obiektów tego samego typu. Stosuje się go głównie w celach optymalizacji, gdyż klonowanie obiektu jest szybsze niż jego stworzenie.
Prototyp - Implementacja
• Implementowanie operacji Clone.
Najtrudniejszym aspektem stosowania wzorca Prototyp jest właściwe zaimplementowanie operacji Clone. Jest to szczególnie skomplikowane, jeśli struktury obiektu obejmują referencje cykliczne.
Większość języków udostępnia pewne mechanizmy do klonowania obiektów. Język C++ udostępnia konstruktor kopiujący (konstruktor, który przyjmuje referencję do obiektu swojego typu i tworzy identyczny obiekt). Jednak mechanizmy te nie rozwiązują problemu płytkiego i głębokiego kopiowania związanego z tym czy klonowanie obiektu spowoduje skopiowanie zmiennych egzemplarza, czy klon i oryginał będą jedynie współużytkować te zmienne. Płytka kopia jest prosta i zwykle wystarczająca. Domyślny konstruktor kopiujący w języku C++ przeprowadza kopiowanie po szczególnych składowych, co oznacza, że wskaźniki będą współużytkowane przez kopii i oryginał. Jednak klonowanie prototypów o złożonych strukturach zwykle wymaga utworzenia głębokiej kopii, ponieważ klon i oryginał muszą być niezależne od siebie. Dlatego trzeba zagwarantować, że komponenty klonu to kopie komponentów prototypu. Klonowanie wymaga zadecydowania, co (jeśli cokolwiek) będzie współużytkowane.
Singleton - nazwa
ang. singleton
Singleton - kategoria
obiektowy, konstrukcyjny
Singleton - Przeznaczenie
Gwarantuje, że klasa będzie miała tylko jeden egzemplarz i zapewnia globalny dostęp do niego.
Singleton - Uzasadnienie
W przypadku niektórych klas ważne jest, aby miały one tylko jeden egzemplarz. Choć w systemie może działać wiele drukarek, powinien znajdować się w nim tylko jeden program buforujący drukowania. Potrzebny jest tylko jeden system plików i menedżer okien, filtr cyfrowy powinien mieć tylko jeden konwerter analogowy-cyfrowy, a system rozliczeniowy powinien być przeznaczony do obsługi tylko jednej firmy
Singleton - Warunki stosowania
- Jeśli musi istnieć dokładnie jeden egzemplarz klasy dostępny klientom w znanym miejscu.
- Kiedy potrzebna jest możliwość rozszerzania jedynego egzemplarza przez tworzenie podklas, a Klienty powinny móc korzystać ze wzbogaconego egzemplarza bez konieczność wprowadzania zmian w ich kodzie.
Singleton - Elementy i współdziałanie
- definiuje operację getInstance() umożliwiającą klientom dostęp do niepowtarzalnego egzemplarza klasy; Instance to operacja statyczna (statyczna funkcja składowa w języku C++);
- może odpowiadać za tworzenie własnego niepowtarzalnego egzemplarza.
Singleton - Współdziałanie
• Klienty mogą uzyskać dostęp do egzemplarza klasy Singleton wyłącznie poprzez operację getInstance() z tej klasy.
Singleton - Konsekwencje
- Zapewnia kontrolę dostępu do jedynego egzemplarza -> Ponieważ klasa Singleton kapsułkuje swój jedyny egzemplarz, można w niej ściśle kontrolować, w jaki sposób i kiedy klienci mogą uzyskać do niego dostęp.
- Pozwala zmniejszyć przestrzeń nazw -> Wzorzec Singleton jest ulepszeniem w porównaniu do zmiennych globalnych. Pozwala uniknąć zaśmiecania przestrzeni nazw zmiennymi globalnymi przechowującymi jedyne egzemplarze.
- Umożliwia dopracowywanie operacji i reprezentacji -> Można tworzyć podklasy klasy Singleton, a ponadto łatwo jest skonfigurować aplikację za pomocą egzemplarza takiej rozszerzonej klasy. Potrzebną do tego klasę można podać w czasie wykonywania programu.
- Umożliwia określenie dowolnego limitu liczby egzemplarzy -> Omawiany wzorzec umożliwia łatwą zmianę podejścia i zezwolenie na tworzenie więcej niż jednego egzemplarza klasy Singleton. Ponadto to samo rozwiązanie można zastosować do kontrolowania liczby egzemplarzy używanych w aplikacji. Trzeba wtedy zmodyfikować jedynie operację, która zapewnia dostęp do egzemplarza klasy Singleton.
- Tworzenie nowej instancji zachodzi dopiero przy pierwszej próbie użycia.
- Brak elastyczności, ponieważ już na poziomie kodu, na „sztywno” określana jest liczba instancji klasy.
Singleton - Implementacja
Zapewnianie niepowtarzalności egzemplarza. We wzorcu Singleton jedyny egzemplarz jest zwykłym egzemplarzem klasy, jednak jest ona napisana tak, aby można utworzyć tylko ten egzemplarz. Standardowe rozwiązanie polega na ukryciu operacji tworzącej egzemplarz w operacji statycznej (czyli statycznej funkcji składowej lub metodzie statycznej), która gwarantuje, że może powstać tylko jeden egzemplarz danej klasy. Ta operacja ma dostęp do zmiennej przechowującej ów egzemplarz, a zanim zwróci jej wartość, upewnia się, że zmienna została zainicjowania za pomocą niepowtarzalnego egzemplarza. To podejście gwarantuje, że singleton zostanie utworzony i zainicjowany przed jego pierwszym użyciem