WYKŁAD 7 Wzorce projektowe strukturalne Adapter Bridge
Structural Design Pattern: Adapter Przekształca interfejs klasy w taki, jakiego oczekuj klienci. Dziki adapterowi istniejce wczeniej klasy mog wspolpracowa, co bez niego byłoby niemoliwe, poniewa maj niezgodne interfejsy. Inne nazwy: Wrapper
Uzasadnienie stosowania: Mamy klas z pakietu narzdziowego. Nie mona jej jednak wykorzysta, poniewa jej interfejs nie pasuje do interfejsu naszej aplikacji specyficznego dla danej dziedziny. Moe to by edytor graficzny, który umoliwia uytkownikom układanie elementów graficznych (linie, figury, tekst) w rysunki i diagramy.
Kady obiekt graficzny moe zmieni kształt lub si narysowa. Interfejs ten jest ustalony przez klas Ksztalt. Dla kadego kształtu mamy podklas (np. KsztaltTekst). KsztaltTekst jest najbardziej skomplikowany, wic nie warto go implementowa. Ale mamy bibliotek z klas WidokTekstu. Jednak klasa ta nie jest zgodna z hierachi klas naszego edytora. Nie da si wic korzytsa wymiennie z obu klas.
Nie moemy zmieni klasy WidokTekstu (brak kodu ródłowego, zmiana w wielu klasach bibliotecznych, dostosowywanie biblioteki do kadego jej wykorzystania). Zamiast tego definiujemy klas KsztaltTekst tak aby adaptowała interfejs klasy WidokTekstu do wymaganego przez nadklas Ksztalt.
Tak adaptacj mona zrealizowa na dwa sposoby: klasowy: wydziedziczenie z interfeksu klasy Ksztalt i z implementacji klasy WidokTekstu [generalizacja] obiektowy: złoenie instancji klasy WidokTekstu z instancj klasy KsztaltTekst i zaimplementowanie klasy KsztaltTekst w kategoriach interfejsu klasy WidokTekstu [asocjacja] Podklas KsztaltTekst nazywamy adapterem.
Edy torgraficzny Ksztalt Ramk abrzegowa() StworzManipulator() +tekst WidokTekstu PodajRozmiar() KsztaltLinia RamkaBrzegowa() StworzManipulator() KsztaltTekst RamkaBrz egowa() St worzmanipulator() return tekst->podajrozmiar return new ManipulatorTekst()
Adapter jest czsto odpowiedzialny równie za implementacj funkcjonalnoci, której nie ma adaptowana klasa. Przykładem moe tu by przeciganie tekstu niezaimplementowane w klasie adaptowanej. Wtedy adapter moe zaimplementowa brakujc funkcjonalno w odpowiedniej podklasie klasy Manipulator, któr musi stworzy.
Stosowalno: zamiar wykorzystania istniejcej klasy gdy jej interfejs nie odpowiada temu, który jest wymagany [strona klienta] zamiar utworzenia klasy wielokrotnego uytku, która współpracuje z niepowizanymi ze sob lub nieprzewidzianymi klasami, tzn. z takimi, które mog mie niezgodne interfejsy [strona biblioteki] adapter obiektów: potrzeba uycia kilku isniejcych podklas, ale zaadaptowanie ich interfejsów przez tworzenie podklas jest niepraktyczne; adapter obiektów moe adaptowa interfejs swojej nadklasy Struktura:
Klient Cel Zadanie() Adaptowany SpecyficzneZadanie() implementacja Adapter Zadanie() SpecyficzneZadanie
Klient Cel +adaptowany Adaptowany Zadanie() SpecyficzneZadanie() Adapter Zadanie() adaptowany->spec yficznezadanie
Uczestnicy: Cel (Ksztalt) definiuje specyficzny dla dziedziny interfejs uywany przez klienta Klient (EdytorGraficzny) współpracuje z obiektami dostosowanymi do interfejsu Celu
Adaptowany (WidokTekstu) definiuje istniejcy wczeniej interfejs, który wymaga zaadaptowania Adapter (KsztaltTekst) adaptuje interfejs Adaptowanego do interfejsu Celu Współpraca: Klienci wywołuj operacje egzemplarza Adaptera. Z kolei adapter wywołuje operacje adaptowane, umoliwiajce spełnienie dania.
Konsekwencje: Adapter klas. adaptuje Adaptowanego do Celu dostosowujc si do klasy konkretnej Adaptowanego nie odpowiedni do adaptowania klasy i wszystkich podklas umoliwia Adapterowi przedefiniowanie czci zachowania Adaptowanego (podklasa) tylko jeden dodatkowy obiekt dla dostpu do Adaptowanego
Adapter obiektów. umoliwia jednemu Adapterowi prac z wieloma Adaptowanymi (tzn. te z podklasami Adaptowanego) moliwo dodania dodatkowej funkcjonalnoci do wszystkich podklas naraz utrudnia przedefiniowanie zachowania Adaptowanego konieczne tworzenie podklas Adaptowanego i odwoływanie si Adaptera do nich, a nie do samego Adaptowanego
Inne zagadnienia: ile pracy adaptacyjnej wykonuje Adapter? tym wicej im wiksze niedopasowanie interfejsów moliwo podłczania Adapterów uycie adapterów dwukierunkowych w celu zapewnienia przeroczystoci
Implementacja: w C++ Adapter dziedziczy publicznie po Celu i prywatnie po Adaptowanym jest podtypem Celu a nie Adaptowanego adaptery podłczalne uywanie operacji abstrakcyjnych uywanie delegatów adaptery sparametryzowane
Przykłady: Znane zastosowania:
Pokrewne wzorce: Bridge podobna struktura, ale przeznaczony jest do odzdzielania interfejsu od implementacji tak aby mogły by zmianiane łatwo i niezalenie. Adapter jest odpowiedzialny za zmian interfejsu istniejcego obiektu.
Decorator ulepsza inny obiekt nie zmieniajc jego interfejsu. Jest dla aplikacji bardziej przeroczysty ni Adapter. Umoliwia ponadto składanie rekurencyjne, co nie jest moliwe w wypadku adapterów w czystej postaci. Proxy definiuje reprezentanta lub substytut innego obiektu i nie zmienia jego interfejsu
Structural Design Pattern: Bridge Wzorzec ten oddziela abstrakcj od jej implementacji, tak by mogły si zmienia niezalenie od siebie nawzajem.
Uzasadnienie: Abstrakcja moe mie wiele implementacji. Naiwne podejcie to definicja klasy abstrakcyjnej jako interfejsu a podklas jako ich rónych implementacji. Przykładowo wyobramy sobie przenon abstrakcj Okno z pakietu narzdziowego do tworzenia GUI.
Chcemy aby klasa ta umoliwiała pisanie aplikacji GUI pod X Window i pod Presentation Manager (PM). Jeli zastosujemy dziedziczenie, to wydziedziczymy z nadklasy Okno podklasy OknowWStyluXa i OknoW StyluPMa implementujce Okno dla obu systemów okienkowych.
Wady tego podejcia s nastpujce: trudno w rozszerzaniu abstrakcji Okno w celu uwzgldnienia rónych rodzajów okien i systemów okienkowych. Dodanie nowego okna: jeli potrzebujemy doda okno reprezentujce ikony, to przy takim podejciu tworzymy podklas klasy Okno o nazwie OknoIkony. Teraz aby mie OknoIkony dla obu systemów okienkowych musimy utworzy podklasy OknoIkonyWStyluXa i OknoIkonyWStyluPMa (=ilo nowych okien*ilo istniejcych stylów). Dodanie nowego stylu: jeli chcemy doda nowy styl, to musimy zaimplementowa dla niego wszytskie wersje okien istniejcych w dotychczasowych stylach (=ilo nowych stylów*ilo istniejcych okien) Czyli jeli dodajemy n okien i m stylów, to musimy zaimplementowa m*n klas
uzalenienie kodu klienta od istniejcych platform trudno w przenoszeniu kodu klienta na inne platformy [podobnie jest z zalenoci klienta od istniejcych okien] Klienci powinni móc tworzy okna niezalenie od konkretnej implementacji. Bridge rozwizuje oba problemy przez umieszczenie abstrakcji Okno i jej implementacji w osobnych hierarchiach, jak pokazano to na rysunku. Nazwa pochodzi od tego, e łczy on abstrakcj z implementacj.
Okno +impl ImplOk na PiszTekst() RysujProstokat() impl->implrysujlinie() impl->implrysujlinie() impl->implrysujlinie() impl->implrysujlinie() ImplPiszTekst() ImplRysujLinie() OknoIkony OknoChwilowe ImplOknaDlaX ImplOknaDlaPM RysujRamke() RysujRamkeZamykajaca() ImplPiszTekst() ImplRysujLinie() ImplPiszTekst() ImplRy sujlinie() RysujProstokat() Pisz Tekst() RysujProstokat() XDrawLine() XDrawString()
Stosowalno: uniknicie stałego powizania abstrakcji z implementacj moliwo wyboru runtime moliwo niezalenego rozbudowywania hierarchii abstrakcji i hierarchii implementacji brak wpływu zmian implementacji na klientów całkowite ukrycie implementacji przed klientem uniknicie namnaania si klas w hierarchiach współdzielenie implementacji przez wiele obiektów Struktura:
Klient Abstrakcja Operacja() +impl Implement acja ImplOperacji() impl->impoperacji RozwinietaAbstrakcja ImplementacjaKonkretnaA ImplOperacji() ImplementacjaKonkretnaB ImplOperacji()
Uczestnicy: Abstrakcja (Okno) definiuje interfejs abstrakcji zarzdza odwołaniem do obiektu typu Implementacja RozwinitaAbstrakcja (OknoIkony) rozszerza interfejs zdefiniowany przez klas Abstrakcja
Implementacja (ImpOkna) definiuje interfejs klas implementujcych, który nie musi dokładnie odpowiada interfejsowi klasy Abstrakcja. Mog si znaczco róni. Zwykle Implementacja okrela operacje pierwotne, a Abstrakcja wykorzystuje je z poziomu operacji wyszego poziomu ImplementacjaKonkretna (ImplOknaDlaX, ImplOknaDlaPM) implementuje interfejs klasy Implementacja i definiuje jej implementacj konkretn
Współpraca: Abstrakcja przesyła dania klientów do swojego obiektu Implementacja Konsekwencje: oddzielenie interfejsu od implementacji mona nie tylko łatwo podmienia operacj, ale nawet mona to robi w czasie wykonania; zmiana implementacji nie wymaga rekompilacji klas Abstrakcja ani Klient zgodno binarna; zachta do architektury warstwowej!
ułatwiona rozszerzalno obie hierarchie mona rozbudowywa niezalenie ukrywanie szczegółów implementacji przed klientami (ukrycie współdzielenia obiektów implementujcych i liczników odwoła) Implementacja: istnienie tylko jednej klasy Implementacja tworzenie właciwego obiektu implementacyjnego w zalenoci od wielkoci (moliwo zmiany runtime) współdzielenie implementacji stosowanie wielodziedziczenia (w C++ zbyt statyczne)
Przykłady: Znane zastosowania: Pokrewne wzorce: AbstractFactory moe tworzy i konfigurowa poszczególne Bridges Adapter dziki niemu niepowizane ze sob klasy mog współpracowa. Zwykle stosuje si go zaraz po zaprojektowaniu systemu. Wzorzec Bridge stosuje si zwykle od samego pocztku projektowania. Dziki niemu niepowizane ze sob klasy mog si zmienia niezalenie od siebie.