Wzorce strukturalne: Fasada, Kompozyt, Most, Pyłek Flashcards
Kompozyt - nazwa
ang. composite
Kompozyt - typ
obiektowy, strukturalny
Kompozyt - Przeznaczenie
Strukturalny wzorzec projektowy, którego celem jest organizacja obiektów w strukturę (hierarchiczną, drzewiastą grupę obiektów) i zdefiniowanie interfejsu wspólnego zarówno dla pojedynczych obiektów jak i grup obiektów.
W ten sposób klient ma możliwość korzystania ze złożonych struktur obiektów w taki sam sposób jak z obiektów pierwotnych (pojedynczych). Ponadto w łatwy sposób można rozszerzać funkcjonalność programu, dodając nowe struktury (komponenty).
Kompozyt - Uzasadnienie
Aplikacje graficzne umożliwiają użytkownikom budowanie złożonych diagramów z prostych komponentów (punkt, linia, tekst). Użytkownik może je łączyć w jeszcze bardziej rozbudowane komponenty. Mimo, że użytkownicy korzystają z obiektów prostych i kontenerowych tak samo, to w kodzie trzeba je traktować w odmienny sposób. Kluczowym elementem wzorca kompozyt jest klasa abstrakcyjna reprezentująca zarówno typy proste i zawierające kontenery
Kompozyt - Warunki stosowania
- przedstawienie hierarchii część-całość
* żeby po stronie klienta można było ignorować różnice między obiektami prostymi i złożonymi
Kompozyt - Elementy
• Komponent (Component):
- klasa abstrakcyjna reprezentująca pojedyncze obiekty (deklaracja interfejsu),
- implementuje domyślne zachowanie na potrzeby interfejsu wspólnego klas,
- obejmuje deklarację interfejsu umożliwiającego dostęp do komponentów podrzędnych i zarządzanie nimi,
- definiuje interfejs umożliwiający dostęp do elementu nadrzędnego dengo komponentu w strukturze rekurencyjnej;
• Kompozyt (Composite):
- przechowuje obiekty podrzędne (Liść),
- implementuje zachowanie elementów które zawiera,
- obejmuje implementację operacji z interfejsu klasy Komponent związanej z elementami podrzędnymi;
• Liść (Leaf):
- typ prosty, nie posiada potomków
Kompozyt - Konsekwencje
- umożliwia definiowanie hierarchii składających się z obiektów prostych i złożonych
- upraszcza kod klientów
- ułatwia dodawanie komponentów nowego rodzaju
- może sprawić, że projekt stanie się zbyt ogólny (ograniczenie dodawania różnych typów prostych)
Kompozyt - Implementacja
- jawne referencje do elementu nadrzędnego (ułatwia poruszanie się po strukturze złożonej) - standardowo zdefiniowane w klasie Komponent
- +- współużytkowanie komponentów - jeśli komponent nie może mieć więcej niż jednego elementu nadrzędnego, stosowanie staje się trudne
- maksymalizowanie interfejsu klasy Komponent (zdefiniowanie jak najwięcej wspólnych cech klas Kompozyt i Liść)
Kompozyt – Powiązane wzorce
- dekorator - jeśli użyte są razem, zwykle mają wspólną klasę nadrzędną
- pyłek - umożliwia współużytkowanie komponentów, które jednak nie przechowują referencji do elementów nadrzędnych
- iterator - do przechodzenia po zawartości kompozytów
- odwiedzający - zapewnia jedną lokalizację dla operacji i zachowań
Most - nazwa
ang. bridge
pol. uchwyt/ciało
ang. handle/body
Most - typ
obiektowy, strukturalny
Most - Przeznaczenie
Oddziela klasę abstrakcji od jej implementacji, dzięki czemu można edytować te elementy niezależnie.
Most - Uzasadnienie
Jeśli abstrakcja może mieć jedną z kilku implementacji, zwykle stosowane jest dziedziczenie. W klasie abstrakcyjnej znajduje się definicja interfejsu abstrakcji, a w konkretnych podklasach — różne implementacje. Jednak to podejście nie zawsze jest wystarczająco elastyczne. Dziedziczenie trwale wiąże implementację z abstrakcją, co utrudnia modyfikowanie, rozszerzanie i wielokrotne korzystanie z tych elementów niezależnie od siebie.
Most - Warunki stosowania
- W celu uniknięcia trwałego powiązania abstrakcji i jej implementacji. Może to być przydatne na przykład wtedy, kiedy implementację trzeba wybrać lub zmienić w czasie wykonywania programu.
- Kiedy rozszerzanie przez tworzenie podklas powinno być możliwe zarówno dla abstrakcji, jak i dla implementacji. Wtedy wzorzec Most umożliwia łączenie różnych abstrakcji i implementacji oraz rozszerzanie ich niezależnie od siebie.
- Jeżeli zmiany w implementacji abstrakcji nie powinny mieć wpływu na klienty (ich kod nie powinien wymagać ponownej kompilacji).
Most - Elementy i współdziałanie
• Abstrakcja (Abstraction):
- definiuje interfejs abstrakcji;
- przechowuje referencję do obiektu typu Implementator.
• WzbogaconaAbstrakcja (RefinedAbstraction):
- rozszerza interfejs zdefiniowany w klasie Abstrakcja.
• Implementator (Implementor):
- definiuje interfejs dla klas z implementacją. Interfejs ten nie musi dokładnie odpowiadać interfejsowi klasy Abstrakcja (różnice między nimi mogą być dość znaczne). Zwykle interfejs klasy Implementator udostępnia jedynie proste operacje, a w klasie Abstrakcja zdefiniowane są oparte na nich operacje wyższego poziomu.
• KonkretnyImplementator (Concretelmplementor):
- obejmuje implementację interfejsu klasy Implementator i definiuje jej implementację konkretną.
Klasa Abstraction przekazuje żądania klienta do powiązanego z nią obiektu Implementator.
Most - Konsekwencje
- Oddzielenie interfejsu od implementacji. Implementacja nie jest trwale powiązana z interfejsem. Implementację abstrakcji można określić w czasie wykonywania programu (można wtedy nawet zmienić implementację obiektu).
- Podział na klasy Abstrakcja i Implementator eliminuje ponadto zależność od implementacji na etapie kompilowania kodu. Zmiana klasy z implementacją nie wymaga ponownej kompilacji klasy Abstrakcja i korzystających z niej klientów.
- Łatwiejsze rozszerzanie. Hierarchie klas Abstrakcja i Implementator można rozszerzać niezależnie od siebie.
- Ukrycie szczegółów implementacji przed klientami. Można ukryć przed klientami szczegóły dotyczące implementacji
Most - Implementacja
Korzystanie z tylko jednej klasy Implementator - jeśli istnieje tylko jedna implementacja, tworzenie abstrakcyjnej klasy Implementator nie jest konieczne. Jest to uproszczona wersja wzorca Most.
Most – Powiązane wzorce
- Do utworzenia i skonfigurowania określonego mostu można użyć wzorca Fabryka abstrakcyjna.
- Wzorzec Adapter jest przeznaczony do umożliwiania współdziałania między niepowiązanymi klasami. Zwykle stosuje się go w systemach po ich zaprojektowaniu, natomiast ze wzorca Most korzysta się przed rozpoczęciem projektowania, aby umożliwić niezależne modyfikowanie abstrakcji i implementacji.
Most - Przykład
• Mostu używa się, by usunąć z układu iloczyn kartezjański klas.
Pyłek - Nazwy
ang. flyweight
Pyłek - typ
obiektowy, strukturalny
Pyłek - Przeznaczenie
Wykorzystuje współdzielenie do wydajnej obsługi dużej liczby małych obiektów.
Pyłek - Uzasadnienie
- W niektórych aplikacjach korzystne jest całkowite oparcie projektu na obiektach, ale koszty naiwnej realizacji mogą okazać się nieakceptowalne.
- W edytorze tekstu, każdy znak może być osobnym obiektem. Wadą jest koszt, znaków mogą być tysiące.
- Pyłek umożliwia korzystanie z obiektu jednocześnie w wielu kontekstach, w każdym działa jak niezależny obiekt.
Pyłek - Warunki stosowania
- aplikacja korzysta z dużej liczby obiektów;
- koszty przechowywania obiektów są wysokie z uwagi na samą ich liczbę;
- większość stanu obiektu można zapisać poza nimi;
- po przeniesieniu stanu za zewnątrz wiele grup obiektów można zastąpić nielicznymi obiektami;
- aplikacja nie jest zależna od tożsamości obiektów (test identyczności zwróci TRUE dla różnych obiektów).
Pyłek - Elementy
• Pyłek (Flyweight):
- obejmuje deklarację interfejsu, przez który pyłki otrzymywać będą zewnętrzny stan
• KonkretnyPyłek (ConcreteFlyweight):
- obejmuje implementację interfejsu i przechowuje wewnętrzny stan, muszą umożliwiać współużytkowanie
• NiewspółużytkowanyKonkretnyPyłek (UnsharedConcreteFlyweight):
- nie wszystkie muszą być współużytkowane, więc ta klasa się pojawia
• FabrykaPyłków (FlyweightFactory):
- tworzy obiekty pyłki i zarządza nimi
- gwarantuje, że pyłki są współużytkowane prawidłowo (jeśli nie ma żądanego pyłku to go stworzy)
• Klient (Client):
- przechowuje referencje do pyłków;
- oblicza lub przechowuje zewnętrzny stan pyłków.
Pyłek - Współdziałanie
Działanie pyłków nie może być zależne od kontekstu. Kluczowym zagadnieniem jest tu rozróżnienie na stan wewnętrzny i zewnętrzny.
Stan wewnętrzny jest zapisywany w pyłku. Składa się z informacji niezależnych od kontekstu pyłku, co umożliwia jego współużytkowanie.
Stan zewnętrzny jest zależny od kontekstu i zmienia się wraz z nim, dlatego nie można go współużytkować. Obiekty klienckie odpowiadają za przekazanie do pyłku zewnętrznego stanu, kiedy jest on potrzebny.
Stan potrzebny pyłkom do działania trzeba podzielić na wewnętrzny i zewnętrzny. Stan wewnętrzny przechowują obiekty ConcreteFlyweight. Stan wewnętrzny jest zapisywany przez obiekty Client lub przez nie obliczany. Klienty przekazują ten stan do pyłku w momencie wywoływania jego operacji. Klienty nie powinny bezpośrednio tworzyć egzemplarzy klas ConcreteFlyweight. Muszą otrzymywać je wyłącznie od obiektu FlyweightFactory, co gwarantuje prawidłowe współużytkowanie obiektów ConcreteFlyweight.
Pyłek - Konsekwencje
- Korzystanie z pyłków może spowodować koszty związanie z przenoszeniem, wyszukiwaniem i obliczaniem stanu zewnętrznego.
- Oszczędność pamięci zależy od zmniejszenia liczby egzemplarzy i wielkości stanu wewnętrznego.
Pyłek - Implementacja
- możliwość usuwania stanu zewnętrznego (jeśli jest tyle stanów co rożnych obiektów to bez sensu)
- zarządzanie współużytkowanymi obiektami - klienty nie powinny tworzyć tych obiektów bezpośrednio tylko przez fabrykę (np. znaki indeksowane w tablicy)
Pyłek – Powiązane wzorce
• kompozyt - często stosowane razem, w celu zaimplementowania logicznie hierarchicznej struktury, ze współdzielonymi węzłami-liśćmi
Fasada - nazwy
ang. fasade
Fasada - typ
obiektowy, strukturalny
Fasada - Przeznaczenie
- Udostępnienie jednolitego interfejsu dla zbioru interfejsów podsystemu.
- Określa interfejs wyższego poziomu ułatwiając korzystanie z podsystemów.
Fasada - Uzasadnienie
Podział systemu na podsystemy pomaga zmniejszyć jego złożoność. Dostęp do wszystkich elementów podsystemów bardzo często jest niepotrzebny, stąd można wystawić jeden uproszczony wysokopoziomowy interfejs.
Fasada - Warunki stosowania
- udostępnienie prostego interfejsu do złożonego podsystemu
- oddzielenie podsytemu/podsystemów od klientów (niezależność podsystemu i możliwość jego przenoszenia między platformami)
- podział podsystemów na warstwy, wtedy fasada jest punktem wejścia do każdej z warstw
Fasada - Elementy i współdziałanie
Fasada (Facade):
- zna klasy podsystemu,
- deleguje żądania do odpowiednich obiektów podsystemu.
• Klasy podsystemu:
- obejmują implementację funkcji podsystemu,
- obsługują zadania przydzielane przez obiekt Fasada,
- nie wiedzą o istnieniu fasady.
Fasada - Konsekwencje
- oddziela klienty od komponentów podsystemu;
- pomaga zachować luźne powiązanie między podsystemem i klientami;
- nie uniemożliwia aplikacjom korzystania z klas podsystemów, jeśli to konieczne.
Fasada - Implementacja
- zmniejszenie powiązania między klientem i podsystemem;
* publiczne i prywatne klasy podsystemu (klasa kapsułkuje stan i operacje, podsystem klasy);