Co to są wzorce projektowe?

Download Report

Transcript Co to są wzorce projektowe?

Wzorce projektowe

wzorce projektowe

autor: Piotr Dziedzic

1

Co to są wzorce projektowe

?

Po co nam te wzorce projektowe?

Kto to wymyślił?

wzorce projektowe

Podział wzorców projektowych Omówienie wzorców na konkretnych przykładach z podziałem na 3 kategorie wzorców czyli……

2

Wzorce kreacyjne Wzorce strukturalne Wzorce behawioralne Źródła informacji na temat wzorców.

Podsumowanie

wzorce projektowe 3

Wzorce projektowe w informatyce wywodzą się z wzorców projektowych w architekturze, które zostały zaproponowane przez amerykańskiego architekta Christophera Alexandra.

„ Wzorzec to sprawdzona koncepcja, która opisuje problem powtarzający się wielokrotnie w określonym kontekście, działające na niego prawa, oraz podaje istotę jego rozwiązania w sposób abstrakcyjny

.”

Christopher Alexander W kontekście architektonicznym (bardzo podobnie jest w informatyce), każdy wzorzec powinien być opisany przez następujące atrybuty: • układ sił działających na niego – czyli środowisko i jego wpływ; • rozwiązanie – schemat konstrukcji, która uwzględnia działające siły, równoważy je i oferuje najlepsze osiągnięcie ; • kontekst - opis warunków, w których rozwiązanie można zastosować; Taki wzorzec jest gotowym schematem postępowania, który można zastosować w wielu sytuacjach, łącząc go także z innymi wzorcami.

wzorce projektowe 4

Sprawdzone w praktyce rozwiązanie często pojawiających się, powtarzalnych problemów projektowych czyli to rozpowszechnione w społeczności programistów danego języka (bądź ogólnie programistów) rozwiązanie powszechnego problemu, sytuacji, z którą możemy się spotkać w czasie projektowania aplikacji.

Wzorzec określa dany problem, prezentując jedno, lub więcej jego rozwiązań. Pokazuje powiązania i zależności pomiędzy klasami oraz obiektami i ułatwia tworzenie, modyfikację oraz pielęgnację kodu źródłowego. Jest opisem rozwiązania, a nie jego implementacją.

Co warto podkreślić : Wzorce projektowe stosowane są w projektach wykorzystujących programowanie obiektowe.

Wartość wzorców projektowych stanowi nie tylko samo rozwiązanie problemu, ale także dokumentacja.

wzorce projektowe 5

• nazwy wzorca; • problemu – opisuje sposoby rozpoznawania sytuacji, w których możemy zastosować dany wzorzec oraz warunki jakie muszą zostać spełnione, by jego zastosowanie miało sens; • rozwiązania technologii; – opisuje elementy rozwiązania: ich relacje, powiązania oraz obowiązki, zawiera także wskazówki implementacyjne dla różnych • konsekwencji – zestawienie wad i zalet stosowania wzorca, uwzględniające informacje o jego brakach oraz kosztach rozwoju i utrzymania systemu wykorzystującego dany wzorzec.

wzorce projektowe 6

• Nazwa wzorca oraz klasyfikacja: według jednego ze schematów.

opisowa oraz unikalna nazwa, umożliwiająca identyfikację oraz odwoływanie się do wzorca; klasyfikacja • Przeznaczenie: opis celu, który stoi za wzorcem oraz powody, jakimi należy się kierować podczas jego wyboru.

• Inne nazwy: jeżeli istnieją inne, dobrze znane nazwy wzorca, należy je podać.

• Motywacja: scenariusz zawierający problem powiązany z kontekstem, w którym wzorzec może być stosowany.

• Stosowalność: sytuacje, w których wzorzec może być użyteczny.

wzorce projektowe 7

Struktura: graficzna reprezentacja wzorca, zwykle jako diagram klas lub diagram interakcji.

Uczestnicy: lista klas i obiektów stosowanych w tym wzorcu oraz ich zobowiązania.

Współpraca: opis wzajemnej interakcji klas i obiektów we wzorcu.

Konsekwencje: wykaz wyników, efektów ubocznych oraz kompromisów jakie występują podczas użycia wzorca.

Implementacja: wskazówki dotyczące implementacji wzorca; zwrócenie uwagi na specyficzne kwestie.

Przykładowy kod: przykład zastosowania wzorca z wykorzystaniem jednego z języków programowania.

Przykłady zastosowania: znane przykłady zastosowania wzorca w rzeczywistych programach.

Pokrewne wzorce: odniesienie wzorca do innych, z którymi wiąże się przez wspólne stosowanie lub można go z nimi zamienić.

wzorce projektowe 8

Szczegółowiej: Wzorce projektowe mogą przyspieszyć proces rozwoju oprogramowania przez dostarczenie wypróbowanych rozwiązań dla problemów, które mogą nie być oczywiste na początku procesu projektowego. Często zagadnienia te wiążą się z ewolucją oczekiwań względem projektowanego systemu: rozszerzeniem jego funkcjonalności, zmianą sposobu i formatu wprowadzanych danych czy dostosowaniem aplikacji do różnych klas użytkowników. Nieuwzględnienie ich na początku procesu rozwoju produktu programistycznego powoduje często konieczność gruntownego przebudowywania zaawansowanego lub gotowego już oprogramowania.

wzorce projektowe 9

Dokładniej - termin wzorca projektowego został wprowadzony do inżynierii oprogramowania przez Kenta Becka oraz Warda Cunninghama w 1987 roku.

Natomiast w 1995 roku autorami pierwszej szeroko znanej publikacji poświęconej wzorcom w inżynierii oprogramowania byli E. Gamma, R. Helm, R.Johnson i J. Vlissides, znani jako Banda Czterech (Gang of Four). W swojej książce opisali 24 wzorce projektowe dotyczące konstrukcji, struktury i zachowania obiektów w systemach informatycznych. Ich zdaniem, poziom abstrakcji wzorca projektowego powinien znajdować się powyżej poziomu pojedynczej klasy.

wzorce projektowe 10

Od tego czasu wzorce projektowe stały się jednym z podstawowych narzędzi projektowania systemów. Powstały nowe, specjalizowane wzorce poświęcone rozwiązaniom dla konkretnych technologii czy platform (np. wzorce dla J2EE).

Panowie z „gangu czterech” w jednej z swoich książek napisali bardzo krótką, a zarazem ujmująca cała istotę sprawy definicję wzorca projektowego:

„Wzorzec projektowy identyfikuje i opisuje pewną abstrakcję, której poziom znajduje się powyżej poziomu abstrakcji pojedynczej klasy, instancji lub komponentu.”

wzorce projektowe 11

Wzorce kreacyjne (creational design patterns)

Wzorce projektowe

Wzorce strukturalne (structural design patterns) Wzorce behawioralne/ czynnościowe (behavioral design patterns) wzorce projektowe 12

Metoda Wytwórcza (Factory Method),

Budowniczy (Builder), Fabryka Abstrakcyjna (Abstract Factory), Prototyp (Prototype), Singleton, Leniwa inicjalizacja (ang. lazy initialization)

Adapter, Dekorator (Decorator), Fasada

(Facade), Kompozyt (Composite), Most (Bridge), Pełnomocnik (Proxy), Pyłek (Flyweight), Kompozyt (Composite)

Interpreter, Metoda Szablonowa (Template

Method), Iterator, Łańcuch Zobowiązań (Chain of Responsibility), Mediator, Obserwator (Observer), Odwiedziający (Visitor), Pamiątka (Memento), Polecenie (Command), Stan (State), Strategia (Strategy)

wzorce projektowe 13

SINGLETON definicja

Według Bandy Czworga:

„Zapewnienie, że klasa posiada tylko jedna instancje oraz dostarczenie globalnego punktu dostępu do tej instancji”

Szczegółowiej: Singleton jest to jeden z kreacyjnych, obiektowych wzorców projektowych, którego celem jest ograniczenie możliwości tworzenia obiektów danej klasy do jednej instancji oraz zapewnienie globalnego dostępu do stworzonego obiektu. Niekiedy wzorzec uogólnia się do przypadku wprowadzenia pewnej maksymalnej liczby obiektów, jakie mogą istnieć w systemie. Niektórzy programiści uznają go za antywzorzec, ponieważ łamie zasady projektowania obiektowego, często bywa nadużywany lub sprowadza się do stworzenia obiektowego zamiennika dla zmiennej globalnej.

przeznaczenie

● do ograniczania możliwości tworzenia obiektów danej klasy do jednej instancji oraz zapewnienie globalnego punktu dostępu do niej.

● używany w sytuacji, gdy istnieje potrzeba stworzenia klasy, która posiadałaby wyłącznie jedną instancję ● użycie zamiast obiektu globalnego - nie zaśmiecany wtedy globalnej przestrzeni nazw różnymi nazwami obiektów.

wzorce projektowe 14

SINGLETON - szczegóły Struktura wzorca

Singleton implementuje się przez stworzenie klasy, która posiada statyczną metodę, która najpierw sprawdza, czy istnieje już instancja tej klasy, w razie potrzeby tworząc ją. Następnie instancja zwracana jest przez referencję. Instancję przechowuje się w prywatnym lub chronionym, statycznym polu, do którego dostęp ma tylko opisana wyżej metoda, która jest jedyną drogą pozyskania instancji obiektu singletonu – aby uniemożliwić tworzenie dodatkowych instancji, konstruktor klasy deklaruje się jako prywatny lub chroniony.

Przykład konkretnego zastosowania

Rozważmy aplikację prowadzącą dla celów diagnostycznych dziennik zdarzeń. Poszczególne komponenty dodają wpis do dziennika, przekazując mu jego treść, natomiast dziennik określa, gdzie faktycznie zostanie on zapisany. Każdy komponent może uzyskać w dowolnym momencie dostęp do dziennika, zatem musi on być dostępny globalnie. To dziennik decyduje o tym, gdzie wpis zostanie faktycznie zapisany. Komponent musi jedynie przekazać jego treść. Oznacza to istnienie pojedynczej instancji dziennika. Z dziennika mogą również korzystać komponenty wielokrotnego użytku, zatem nie powinny one być zależne od mechanizmów udostępniania zasobów specyficznych dla danej aplikacji.

Możemy to zapewnić, implementując w dzienniku wzorzec singleton tak, aby mógł on we własnym zakresie zarządzać dostępem do siebie samego.

wzorce projektowe 15

SINGLETON – zalety i wady zalety

● singleton nie musi ograniczać się do obsługi pojedynczej instancji klasy – przy niewielkiej zmianie podejścia można za jego pomocą zarządzać także większą liczbą obiektów, ● klasa zaimplementowana z użyciem wzorca singleton może samodzielnie kontrolować liczbę swoich instancji istniejących w systemie, ● proces pobierania instancji klasy jest niewidoczny dla użytkownika. Nie musi on wiedzieć, czy w chwili wywołania metody instancja istnieje czy dopiero jest tworzona, ● tworzenie nowej instancji ma charakter leniwy, tj. zachodzi dopiero przy pierwszej próbie użycia. Jeśli żaden komponent nie zdecyduje się korzystać z klasy, jej instancji nie będą niepotrzebnie przydzielone zasoby.

wady

● brak elastyczności bo już na poziomie kodu jest na sztywno określona liczba instancji jakie mogą istnieć w systemie; ● poważnie utrudnia testowanie aplikacji przez wprowadzenie do niej globalnego stanu łamie zasadę jednej odpowiedzialności; ● łamie zasadę otwarte-zamknięte nie można go rozszerzyć;

wzorce projektowe 16

FABRYKA ABSTRAKCYJNA (ang. Abstract Factory)

definicja

Według Bandy Czworga:

„Dostarczenie interfejsu służącego do tworzenia rodzin powiązanych ze sobą obiektów bez konieczności wyspecyfikowania ich klas konkretnych”

Szczegółowiej: obiektów.

jest to jeden z kreacyjnych wzorców projektowych (obiektowy), którego celem jest dostarczenie interfejsu do tworzenia różnych obiektów jednego typu (tej samej rodziny) bez specyfikowania ich konkretnych klas. Umożliwia jednemu obiektowi tworzenie różnych, powiązanych ze sobą, reprezentacji podobiektów określając ich typy podczas działania programu. Fabryka abstrakcyjna różni się od Budowniczego, tym, że kładzie nacisk na tworzenie produktów z konkretnej rodziny, a Budowniczy kładzie nacisk na sposób tworzenia

przeznaczenie

● Wzorzec fabryki abstrakcyjnej stosujemy, kiedy zachodzi potrzeba skoordynowania procesów tworzenia rodzin obiektów. ● Wzorzec ten pozwala na wyodrębnienie reguł dotyczących tworzenia obiektów z obiektów użytkownika, które będą wykorzystywać tworzone obiekty.

● Ułatwia tez przystosowywanie kodu źródłowego do pracy w zróżnicowanych środowiskach. System tworzy nową unikatową konkretną fabrykę (która z kolei tworzy nowy unikatowy produkt) dla każdego środowiska, ale ponieważ korzystasz w swoim kodzie wyłącznie z interfejsów, zagwarantowanie właściwej współpracy konkretnymi środowiskami nie jest twoim zmartwieniem.

wzorce projektowe 17

FABRYKA ABSTRAKCYJNA - szczegóły

Struktura wzorca

Jak widać na załączonym diagramie klas wzorzec zbudowany jest z kilku podstawowych klas. Klasa Fabryka abstrakcyjna deklaruje abstrakcyjny interfejs umożliwiający tworzenie produktów. Interfejs ten jest implementowany w Fabrykach konkretnych, które odpowiedzialne są za tworzenie konkretnych produktów. Każda fabryka konkretnego produktu posiada także metodę wytwórczą tego produktu.

Przykłady konkretnych zastosowań (implementacji)

1) Przykładem może być fabryka elementów wizualnych GUI – okien, kursorów, ikon. Produkty różnią się implementowanymi interfejsami (np. IWindow, ICursor, IImage) ale nadal leżą w tym samym obszarze – GUI.

2) Rozpatrzmy aplikację kliencką, która łączy się ze zdalnym serwerem. Celem projektanta takiej aplikacji jest to, aby była ona przenośna. Jednym z rozwiązań takiego problemu jest stworzenie fabryki, która będzie tworzyła odpowiednie obiekty w zależności od tego na jakiej platformie się znajduje.

wzorce projektowe 18

FABRYKA ABSTRAKCYJNA – zalety i wady

plusy

● Jednym z plusów wykorzystania wzorca jest możliwość ukrycia szczegółów implementacyjnych klas reprezentujących konkretny produkt - klient widzi tylko interfejs. Ukryciu ulegają także nazwy tych klas, co nie wymusza ich zapamiętywania i odizolowuje klienta od problemu określenia do której klasy należy obiekt.

Do zysków należy także możliwość całkowitego ukrycia implementacji obiektów przed klientem. Klient widzi tylko interfejs i nie ma możliwości zajrzenia do kodu oraz to, że wymuszana jest spójność produktów.

minusy

● Do minusów należy zaliczyć trudność rozszerzania rodziny obiektów o nowe podobiekty. Wymusza to modyfikację klasy fabryki abstrakcyjnej oraz wszystkich obiektów, które są tworzone przez nią. ● Jeśli dany produkt nie realizuje powierzonych mu zadań zgodnie z oczekiwaniami, z reguły jest się zmuszonym do zmiany interfejsu abstrakcyjnego produktu , co zwykle jest dosyć trudne, ponieważ wymaga zmodyfikowania definicji wszystkich konkretnych produktów.

wzorce projektowe 19

BUDOWNICZY(ang. Builder)

definicja

Według Bandy Czworga:

„Wzór budowniczy służy do utworzenia obiektów złożonych z części składowych, które muszą zostać utworzone w tym samym celu i przy użyciu określonego algorytmu. Klasa kontroluje zewnętrzny algorytm budowy”.

Szczegółowiej : Budowniczy jest to jeden z kreacyjnych wzorców projektowych (obiektowy), którego celem jest rozdzielenie sposobu tworzenia obiektów od ich reprezentacji. Dzięki takiemu rozwiązaniu w tym samym procesie konstrukcyjnym możemy tworzyć różne reprezentacje obiektów. Budowniczy różni się od wzorca fabryki abstrakcyjnej oraz pozostałych wzorców kreacyjnych tym, że skupia się na sposobie tworzenia obiektów reprezentujących produkty. Budowniczy tworzy drobną częśc skomplikowanego produkt za każdym swoim wywołaniem jednoczesnie kontrolując stan wykonanej pracy. Klient dostaje produkt po zakończeniu pracy Budowniczego a nie - tak jak w przypadku Fabryki abstrakcyjnej "od razu".

przeznaczenie

● Wzorzec budowniczego stosowany jest do oddzielenia sposobu tworzenia obiektów od tego jak te obiekty mają wyglądać.

● Gdy chcemy sobie zagwarantować możliwość łatwego dodawania obsługi nowego formatu danych wyjściowych, zapobiegając jednocześnie jakimkolwiek modyfikacjom klasy zarządzającej obiektami budowniczymi.

● chcemy przekonwertować te same dane do kilku różnych postaci

wzorce projektowe 20

BUDOWNICZY- szczegóły

Struktura wzorca

Jak widać na przedstawionym diagramie klas wzorzec składa się z dwóch podstawowych obiektów. Pierwsza z nich oznaczony jest jako Budowniczy - jego celem jest dostarczenie interfejsu do tworzenia produktów. Drugim obiektem jest obiekt oznaczony jako Konkretny Budowniczy a jego celem jest tworzenie konkretnych produktów korzystając z interfejsu obiektu Budowniczy. Strukturę wzorca uzupełnia obiekt Kierownika, wydaje on polecenia konstrukcji produktów wykorzystując do tego obiekt Budowniczego

Przykłady konkretnych zastosowań (implementacji)

1) Różne warianty omawianego wzorca wykorzystywane są w bibliotece MFC, implementując architekturę dokument/widok. Obiekt klasy CDocument oraz jego podobiekty tworzone są poprzez wywołanie metody tworzącej z trzema parametrami typu CRuntimeClass. Klasa ta zawiera metodę CreateObject, umożliwiającą jej tworzenie obiektów różnych klas . Dzięki takiemu zachowaniu CRuntimeClass może być nazwana klasą Budowniczego. 2) Przykładem może być też oprogramowanie konwertujące tekst z jednego formatu na drugi. Algorytm odczytujący i interpretujący dane wejściowe jest oddzielony od algorytmu tworzącego dane wyjściowe. Dzięki takiemu rozwiązaniu możemy stosować jeden obiekt odczytujący dane wejściowe oraz wiele obiektów zapisujących je w różnych formatach (ASCII, HTML, RTF, itp.)

wzorce projektowe 21

BUDOWNICZY– zalety i wady

Plusy dodatnie

● Do plusów stosowania wzorca należą: duża możliwość zróżnicowania wewnętrznych struktur klas oraz możliwość kontrolowania tworzenia obiektów po stronie klienta.

Stosowanie wzorca zapobiega także tworzeniu zduplikowanego kodu odpowiedzialnego za tworzenie obiektów, gdyż proces tworzenia konkretnych elementów obiektów zamknięty jest w poszczególnych procedurach.

duża skalowalność (dodawanie nowych reprezentacji obiektów jest uproszczone)

Plusy ujemne

● Minusem jest duża liczba obiektów reprezentujących konkretne produkty.

● Ewentualna zmiana interfejsu budowniczego wiąże się z koniecznością zmodyfikowania wszystkich implementujących klas.

wzorce projektowe 22

PROTOTYP (ang. Prototype) definicja

Wzorzec projektowych, którego celem jest umożliwienie tworzenia obiektów danej klasy bądź klas z wykorzystaniem już istniejącego obiektu, zwanego prototypem. Głównym celem tego wzorca jest uniezależnienie systemu od sposobu w jaki tworzone są w nim produkty.

przeznaczenie

Wzorzec Prototyp powinien być używany, gdy: ● system powinien być niezależny od tego, jak jego produkty są tworzone, składane i reprezentowane; ● klasy, których egzemplarze należy tworzyć są specyfikowane w czasie wykonywania programu, np. przez dynamiczne ładowanie.

● istnieje potrzeba uniknięcia budowania hierarchii klas fabryk, która jest porównywalna z hierarchią klas produktów ● stan obiektów klasy może przyjmować tylko jedną z kilku różnych wartości; może być wówczas wygodniej zainstalować odpowiednią liczbę prototypów i klonować je niż ręcznie tworzyć egzemplarze klasy za każdym razem z odpowiednim stanem.

wzorce projektowe 23

PROTOTYP - szczegóły

Struktura wzorca

Wzorzec prototypu określa rodzaj obiektów do tworzenia za pomocą prototypowej instancji. Prototypy nowych produktów są często budowane przed pełną produkcją, ale w tym przykładzie, prototyp jest bierny i nie bierze udziału w kopiowaniu siebie samego. Prototyp - deklaruje interfejs klonowania się.

PrototypKonkretny klonowania się. - implementuje operację Klient - tworzy nowy obiekt, prosząc prototyp o sklonowanie się. Współpraca prosi prototyp o sklonowanie się.

- Klient

Przykłady konkretnych zastosowań (implementacji)

Projekty, które intensywnie używają wzorca Kompozytu i Dekoratora, mogą równie dobrze odnieść korzyść ze stosowania Prototypu.

Praktyczną wskazówką na to, kiedy może być potrzebnym używanie metody clone(), jest konieczność tworzenia prawdziwej kopii (ang. true copy) innej instancji w czasie wykonywania programu. Prawdziwa kopia to taka, w której skopiowany obiekt ma wszystkie swe pola identyczne z pierwowzorem. Gdy używa się operatora new, to wtedy te pola mają wartości początkowe. Przykładowo, jeśli projektuje się system do przeprowadzania transakcji bankowych, to wtedy potrzebna jest taka kopia obiektu, która przechowa dane konta, wykona transakcje na tej kopii i zamieni tę kopię z oryginałem. W takim przypadku potrzebna jest raczej metoda clone() niż operator new.

wzorce projektowe 24

PROTOTYP– zalety i wady

Plusy dodatnie

● Prototyp może skrócić czas tworzenia obiektów.

Można zainstalować nowy konkretny produkt w ramach wytwórni przez proste przekazanie tej wytwórni prototypu ( już w czasie wykonania programu). Usuwanie produktów jest równie łatwe.

Plusy ujemne

● Trzeba wprost interpretować metodę clone(), co w niektórych przypadkach może być dość trudne. Należy też rozważyć problem głębokiej lub płytkiej kopii. (Czy Twoja kopia powinna się sprowadzać do referencji, czy raczej należy klonować cały wskazany obiekt?) I wreszcie metodę klonująca powinna niekiedy działać jak konstruktor –inicjalizować pewne pola wartościami domyślnymi. Przykładowo, klon pola listy zwykle nie może się znaleźć na liście.

wzorce projektowe 25

Metoda wytwórcza (ang. factory method)

Definicja: Jeden z kreacyjnych wzorców projektowych (klasowy), którego celem jest dostarczenie interfejsu do tworzenia obiektów nieokreślonych jako powiązanych typów. Tworzeniem

egzemplarzy zajmują się podklas.

Ten wzorzec projektowy stosuje się gdy: ●

klasa potomna ma decydować jaki obiekt ma zostać stworzony przez klasę bazową;

nie da się określić jakie obiekty powinny być tworzone przez klasę bazową;

chcemy ukryć implementację

Leniwa inicjalizacja (ang. lazy initialization)

Definicja: Wzorzec projektowy, który opóźnia tworzenie obiektu do chwili w której następuje pierwsze jego użycie. Niniejszy wzorzec jest ściśle powiązany ze wzorcem projektowym metoda wytwórcza.

Zastosowanie: ● ● gdy chcemy zapewnić istnienie obiektu w chwili jego użycia; nie chcemy pamiętać o konieczności tworzenia obiektu.

wzorce projektowe 26

MOST (ang. Bridge)

definicja

Wzorzec projektowy, pozwalający na modyfikowanie implementacji oraz abstrakcji w czasie działania programu. Interfejs zostaje całkowicie odizolowany od swojej implementacji. Dzięki temu zyskujemy możliwość oddzielnego modyfikowania abstrakcji oraz oddzielnej modyfikacji implementacji. Implementacja w opisie mostu oznacza obiekty, których używa klasa abstrakcyjna i klasy jej pochodne (nie same klasy pochodne).

przeznaczenie

● ● ● ● Według Bandy Czworga intencja mostu jest:

„Usunięcie powiązań pomiędzy abstrakcją i implementacją, aby obie mogły zmieniać się niezależnie”

, czyli konsekwencją stosowania mostu jest umożliwienie odrębnej ewolucji Abstrakcji (np. poprzez dziedziczenie) i jej implementacji – możemy np. łatwo dodać nową implementację do całej hierarchii klas dziedziczących po Abstrakcji Zaleca się stosowanie tego wzorca aby:

odseparować implementację od interfejsu, poprawić możliwości rozbudowy klas, zarówno implementacji, jak i interfejsu (m.in. przez dziedziczenie), ukryć implementację od klienta, co umożliwia zmianę implementacji bez zmian interfejsu,

do zapewnienia niezależności aplikacji od platformy.

wzorce projektowe 27

MOST - szczegóły

Struktura wzorca

Elementy tworzące strukturę tego wzorca to: Abstrakcja: niezależny od podsystemu portal do kodu właściwego dla danego systemu, RozwiniętaAbstrakcja(Udoskonalona abstrakcja): często pomijana wersja abstrakcji, którą dostosowano do potrzeb konkretnej aplikacji, Implementacja(Implementator): implementator): właściwa dla danego podsystemu.

interfejs wykorzystywany przez abstrakcję do komunikowania się z implementacją właściwą dla odpowiedniego podsystemu. Interfejs ten zwykle pełni tez funkcję abstrakcyjnego produktu w ramach wzorca wytwórni abstrakcji , ImplementacjeKonkretne( Konkretny implementacja implementatora

Przykład konkretnych zastosowań (implementacji)

Wyobraźmy sobie abstrakcję jaką jest figura. Można ją wyszczególnić na np. kwadraty, czy trójkąty, jednak są pewne metody dla każdej figury jak np. rysowanie. Jednak rysowanie może być różne dla różnych bibliotek graficznych czy systemów operacyjnych. Wzorzec mostu pozwala na stworzenie nowych klas, które dostarczają konkretnych implementacji do rysowania. Klasa abstrakcyjna figury dostarcza informacji o figurze (np. wielkość), podczas gdy implementacja dostarcza interfejs do rysowania. Przydatny może być w sytuacji, gdy graficzny interfejs użytkownika (GUI) musi wyglądać inaczej w zależności od posiadanego systemu operacyjnego. Zmiany w kodzie mają charakter dynamiczny (wszystkie modyfikacje dokonywane są w trakcie działania programu).

wzorce projektowe 28

MOST– plusy i minusy

Plusy

● W czystym modelu dziedziczenia trzeba by korzystać z nadklasy implementującej pewne zachowania oraz zbioru podklas, których zachowanie byłoby dostosowane do potrzeb poszczególnych platform. We wzorcu projektowym mostu taka nadklasa jest w praktyce zastępowana interfejsem, zatem w rozwiązaniach opartych na tej technice problemy związanie z dziedziczeniem implementacji są zminimalizowane, a łączna liczba klas ograniczona.

minusy

● Implementowanie interfejsów w taki sposób, aby każda implementacja zachowywała się tak samo jest stosunkowo trudne. Most podsystemu AWT języka Java implementuje komponenty okien dla różnych środowisk operacyjnych, ale np. implementacja dla systemu Motif zachowuje się trochę inaczej niż implementacja dla systemu Windows.

wzorce projektowe 29

DEKORATOR (ang. Decorator)

definicja

Według Bandy Czworga intencją dekoratora jest :

„Dodanie nowych rodzajów odpowiedzialności do obiektu w dynamiczny sposób. Dekorator oferuje rozwiązania alternatywne do tworzenia klas pochodnych w celu rozszerzenia funkcjonalności obiektu”.

Szczegółowiej: Jest to wzorzec, który pozwala na dodanie nowej funkcjonalności do istniejących klas dynamicznie podczas działania programu. Wzorzec dekoratora polega na opakowaniu oryginalnej klasy w nową klasę "dekorującą". Zwykle przekazuje się oryginalny obiekt jako parametr konstruktora dekoratora, metody dekoratora wywołują metody oryginalnego obiektu i dodatkowo implementują nową funkcjonalność.

przeznaczenie

● Dekoratory są alternatywą dla dziedziczenia. Dziedziczenie rozszerza zachowanie klasy w trakcie kompilacji, w przeciwieństwie do dekoratorów, które rozszerzają klasy w czasie działania programu.

● Do ulepszania i rozbudowywania obiektów. Załóżmy, że chcemy dodać do jakiejś klasy metodę (niech jeszcze będzie to abstrakcja lub metoda wirtualna, a klasa ta będzie nadklasą dla innych klas). Dzięki dekoratorowi nie musimy tutaj nic modyfikować, możemy nadać obiektowi nowe zachowanie podczas działania programu. ● Dodatkowo wzorzec ten zapobiega przed eksplozją klas, spowodowaną dużą liczbą rozszerzeń danej klasy (np. kombinacji rożnych składników na pizzy może być mnóstwo), czyli dekorator ułatwia rozbijanie wielkich , złożonych operacji na operacje mniejsze, prostsze.

wzorce projektowe 30

DEKORATOR - szczegóły

Struktura wzorca

Elementy tworzące strukturę tego wzorca to: Komponent: odpowiedzialności (lub do modyfikowania swojego zachowania) w czasie wykonywania programu, interfejs dla obiektów przystosowanych do przejmowania nowych zakresów Konkretny komponent: obiekt, do którego są dołączone nowe zakresy odpowiedzialności lub nowe zachowania, Dekorator: opakowuje komponent i definiuje interfejs z jednej strony dostosowany do interfejsu tego komponentu, ale jednocześnie zachowujący się w nieco inny sposób, Konkretny dekorator: rozszerza dekorator celem zdefiniowania dodatkowych zachowań.

wzorce projektowe 31

Przykład konkretnego zastosowania (implementacji):

Rozważmy okno w graficznym interfejsie użytkownika (GUI): By pozwolić na przewijanie jego zawartości, należy dodać do niego poziome lub pionowe paski przewijania. Okna są reprezentowane przez instancje klasy Okno i klasa ta nie powinna posiadać żadnych metod dodających paski przewijania. Można utworzyć podklasę PrzewijaneOkno, która udostępniałaby te metody lub stworzyć OknoDekoratorPrzewijane, który jedynie dodawałby tę funkcjonalność do istniejących obiektów Okno. W tym miejscu działałyby oba rozwiązania.

Teraz załóżmy, że potrzeba dodać ramki dookoła okien. I w tym przypadku klasa Okno nie ma takiej funkcjonalności. Pojawia się problem z podklasą OknoPrzewijane, bo aby dodać ramki do wszystkich okien potrzeba stworzyć podklasy OknoZRamką i OknoPrzewijaneZRamką. Problem staje się jeszcze większy z każdą kolejną opcją. W przypadku dekoratorów wystarczy stworzyć jedną klasę OknoDekoratorRamka - podczas działania programu można dynamicznie dekorować istniejące okna z OknoDekoratorPrzewijane lub OknoDekoratorRamka lub oboma.

wzorce projektowe 32

DEKORATOR– zalety i wady

zalety

● Rozmiar i zależność hierarchii klas jest znacznie ograniczona ● Wysoka elastyczność (w odróżnieniu od dziedziczenia) ● Unikanie przeładowanych właściwościami klas na szczycie hierarchii

wady

● Funkcjonalność wprowadzana w ramach dekoratora (np. mechanizm zwracania znaków do strumienia danych wejściowych) stwarza pewne trudności (lub nawet zagrożenia) w zakresie uzyskiwania dostępu, jeśli dekorator sam jest dekorowany. W tego typu systemach zasadnicze znaczenie ma kolejność stosowania dekoratorów. Przykładowo, klasa PushbackInputStream języka Java zdaje egzamin w skrajnie zewnętrznej warstwie, ale już w wersji opakowanej w ramach klasy BufferedInputStream po prostu nie działa (nie zwraca znaków do bufora).

wzorce projektowe 33

FASADA-(ang. Facade)

definicja

Według Bandy Czworga :

„Dostarczenie jednolitego interfejsu do zbioru interfejsów pewnego podsystemu. Fasada definiuje bardziej ogólny interfejs, ułatwiając w ten sposób wykorzystanie podsystemu”.

Fasada to wzorzec, który służy do ujednolicenia dostępu do złożonego systemu poprzez wystawienie uproszczonego, uporządkowanego interfejsu programistycznego, który ułatwia jego użycie. Fasada jest obiektem pośredniczącym między klasami klienta wywołującego operacje a klasami, które te operacje wykonują.

przeznaczenie

Wzorzec fasady wykorzystuje się : ● aby ukryć złożoność tworzonego systemu przez dostarczenie udokumentowanego, publicznego API. Definiujemy dozwolony dostęp do API przez co redukujemy ilość możliwych przypadków błędnego użycia. Programiści muszą przyswoić sobie API fasady a nie całego systemu. Bardzo przydaje się to wtedy, gdy biblioteka jest długo rozwijana i jest duża ilość przedawnionych metod. Fasada odświeża API skupiając się jedynie na operacjach aktualnych .

● aby uprościć używanie cudzej biblioteki. Definiuje się wygodne, dostosowane do konkretnego zastosowania metody pośredniczące między systemami. Zwiększa się czytelność kodu.

ukryć implementację przed klientem, co umożliwia zmianę implementacji bez zmian interfejsu,

● aby poprawić użyteczność biblioteki ze źle skonstruowanym API przez stworzenie nakładki, która dostarcza nowe, uporządkowane API.

wzorce projektowe 34

FASADA- szczegóły

Struktura wzorca

Wzorzec wyróżnia następujące elementy: złożony system – reprezentowany na diagramie przez klasy Element1 do Element5. Chcemy uprościć dostęp do niego, fasada – klasa posiadająca referencje do elementów systemu z metodami do wykonywania najczęściej potrzebnych zadań, klient – dowolny kod zainteresowany wykorzystaniem złożonego systemu.

Klient komunikuje się z systemem poprzez fasadę, która w jego imieniu wykonuje niezbędne operacje na złożonym systemie. To, czy klient posiada także bezpośredni dostęp do systemu, leży w gestii programisty implementującego wzorzec.

Przykład konkretnego zastosowania (implementacji)

Przykładem użycia wzorca fasady może być aplikacja bankomatowa, która musi wchodzić w interakcję z systemem bankowym. Skoro aplikacja bankomatowa wykorzystuje tylko niewielką część możliwości systemu bankowego (autoryzacja karty, sprawdzenie stanu konta, wypłata i ew. wpłata), to można zastosować obiekt fasady, który zasłoni przed zewnętrznymi aplikacjami skomplikowaną strukturę wewnętrzną systemu bankowego. Upraszcza to pisanie aplikacji na bankomaty, a jednocześnie zapewnia lepsze bezpieczeństwo systemu bankowego.

wzorce projektowe 35

FASADA– plusy dodatnie i plusy ujemne

Plusy dodatnie

● Zmniejszenie liczby zależności między klientem, a złożonym systemem — jeśli klient nie korzysta bezpośrednio z żadnych elementów ukrytego za fasadą systemu, całość jest łatwiejsza w konserwacji i utrzymaniu.

● Wprowadzenie podziału aplikacji na warstwy, który ułatwia niezależny rozwój elementów klienta i złożonego systemu.

● Możliwość zablokowania klientowi drogi do bezpośredniego korzystania ze złożonego systemu, jeśli jest to konieczne.

● Kod klienta wykorzystującego fasadę jest czytelniejszy i łatwiejszy w zrozumieniu

Plusy ujemne

● Praktycznie nie ma wad. Za „wadę” można uznać to, że mimo zastosowania fasady programista i tak może korzystać z klas podsystemu bezpośrednio.

wzorce projektowe 36

Adapter (ang. adapter )

Intencja Adaptera wg Bandy Czworga:

„Dostosowanie interfejsu klasy do interfejsu, którego oczekuje użytkownik. Adapter umożliwia współprace klas, która bez jego zastosowania nie byłaby możliwa ze względu na ich niezgodne interfejsy.”

Szczegółowiej: Wzorzec Adapter konwertuje interfejs jednej klasy na interfejs innej klasy. Używamy tego wzorca, jeśli chcemy, żeby dwie niezwiązane ze sobą klasy współpracowały ze sobą w jednym programie. Koncepcja wzorca Adaptera jest bardzo prosta: piszemy klasę, która posiada wymagany interfejs, a następnie zapewniamy jej komunikację z klasą, która ma inny interfejs. Istnieją dwa sposoby realizacji: poprzez dziedziczenie i poprzez kompozycję.

Ten wzorzec projektowy stosuje się gdy: ● klasa nie może być użyta ponieważ ma niekompatybilny interfejs ● gdy nie mamy kodu źródłowego klas nie możemy zmienić ich interfejsu a nawet jeśli mamy kod źródłowy klasy nie powinniśmy raczej zmieniać interfejsu klasy!

Kompozyt (ang Composite)

Definicja: Wzorzec projektowy, którego celem jest składanie obiektów w taki sposób, aby klient widział wiele z nich jako pojedynczy obiekt. Pozwala traktować jednakowo obiekty jak i grupy obiektów. Aplikacji dostarczają możliwość grupowania obiektów, jednak wykonanie operacji na pojedynczych obiektach i ich kontenerach są różne. Kompozyt definiuje interfejs, który jest wspólny zarówno dla pojedynczych jednostek jak i ich grup. W interfejsie tym są zdefiniowane wszystkie metody charakterystyczne dla obu tych obiektów przez co są traktowane tak samo przez klienta, ale implementacja tych metod jest różna w pojedynczych obiektach niż w grupach. Zastosowanie: Wzorzec kompozyt wykorzystuje się najczęściej w sytuacji gdy chcemy reprezentować całą hierarchię obiektów lub tylko część hierarchii), lub gdy chcemy aby klient nie widział różnicy między pojedynczym obiektem a ich kolekcją. Klient będzie traktował wszystkie obiekty jednakowo.

wzorce projektowe 37

Pełnomocnik (ang. Proxy)

Definicja: Wzorzec projektowy, którego celem jest utworzenie obiektu zastępującego inny obiekt. Stosowany jest w celu kontrolowanego tworzenia na żądanie kosztownych obiektów oraz kontroli dostępu do nich.

Ten wzorzec projektowy stosuje się gdy: ● Pełnomocnik ma zastosowanie zawsze wtedy, kiedy potrzeba bardziej uniwersalnego lub bardziej wyrafinowanego odwołania do obiektu niż zwykły wskaźnik.

● Istnieją cztery rodzaje tego wzorca, które jednocześnie definiują sytuacje, w których może zostać użyty: wirtualny przechowuje obiekty, których utworzenie jest kosztowne; tworzy je na żądanie; pamięci.

ochraniający kontroluje dostęp do obiektu sprawdzając, czy obiekt wywołujący ma odpowiednie prawa do obiektu wywoływanego; zdalny czasami nazywany ambasadorem; reprezentuje obiekty znajdujące się w innej przestrzeni adresowej; sprytne odwołanie czasami nazywany sprytnym wskaźnikiem; pozwala na wykonanie dodatkowych akcji podczas dostępu do obiektu, takich jak: zliczanie referencji do obiektu czy ładowanie obiektu do

wzorce projektowe 38

Pyłek (Waga piórkowa, ang. Flyweight)

Definicja: Jest wzorcem strukturalnym, który rozszerza niejako wzorzec puli obiektów. Pula obiektów przechowuje nierozróżnialne obiekty gotowe do użycia – niemożliwe jest przechowywanie w nich informacji specyficznej. Pyłek stosowany jest do tworzenia bardzo dużej liczby obiektów (niewiele się różniących lub identycznych), którymi można zarządzać w sposób jednolity. Wzorzec tworzy jedyną instancję danego obiektu, którą następnie można modyfikować – zmieniać wartości określonych jego atrybutów (tylko to, co uległo zmianie). W ten sposób klient odczytuje dokładnie taki obiekt, jakiego oczekuje, nie powodując zwiększenia zużycia zasobów. Efektem tego jest zmniejszenie zapotrzebowania aplikacji na pamięć. Istotą tego wzorca jest podział danych przechowywanych w obiektach na dane wewnętrzne (współdzielone) i zewnętrzne (unikatowe dla każdego obiektu). Dane wewnętrzne nie są modyfikowane przy inicjacji obiektu, natomiast dane zewnętrzne są dostarczane dla każdego obiektu z zewnątrz (np. poprzez odczyt z bazy danych) przed przekazaniem do klienta.

Zastosowanie : Wzorzec Pyłek stosuje się tam, gdzie klasa ma wiele egzemplarzy, a każdy z tych egzemplarzy może być sterowany w ten sam sposób. Przykład zastosowania można znaleźć w aplikacji wspomagającej modelowanie przestrzennego terenu. W takim muszą się znaleźć obiekty reprezentujące drzewa. Nawet jeśli te obiekty będą bardzo proste (np. będą zawierać tylko wysokość i współrzędne położenia drzewa), to przy modelowaniu wielkich kompleksów zieleni, gdzie takich obiektów potrzebne będą ogromne ilości, aplikacja zacznie działać bardzo wolno. Dlatego w tego typu aplikacjach stosuje się wzorzec Pyłek i zamiast tworzyć wiele egzemplarzy drzew, tworzy się jeden obiekt, który przechowuje stany (współrzędne, wysokość) wszystkich drzew w tablicy.

wzorce projektowe 39

METODA SZABLONOWA (ang. Template Method)

definicja

Według Bandy Czworga : Szczegółowiej:

„Zdefiniowanie ogólnego szkieletu używanego algorytmu i pozostawienie implementacji niektórych jego kroków dla klas pochodnych. Dzięki temu uzyskuje się możliwość modyfikacji niektórych kroków algorytmu bez konieczności zmieniania jego ogólnej struktury”.

zadaniem tego wzorca jest zdefiniowanie metody będącej szkieletem algorytmu – algorytm ten może być następnie dokładnie definiowany w klasach pochodnych. Niezmienna część algorytmu zostaje opisana w metodzie szablonowej, której klient nie może nadpisać. W metodzie szablonowej wywoływane są inne metody, reprezentujące zmienne kroki algorytmu. Mogą one być abstrakcyjne lub definiować domyślne zachowania. Klient, który chce skorzystać z algorytmu, może wykorzystać domyślną implementację bądź może utworzyć klasę pochodną i nadpisać metody opisujące zmienne fragmenty algorytmu.

przeznaczenie

Wzorzec metody szablonowej wykorzystuje się : ● zwykle w szkieletach aplikacji opartych na mechanizmie dziedziczenia. Taki szkielet zawiera zbiór nadklas odpowiadających za realizację około 90 procent wszystkich zadań, a jego celem jest przeniesienie operacji właściwych dla konkretnej aplikacji na poziom metod abstrakcyjnych. Oznacza to, że metody wspomnianych nadklas musza wywoływać abstrakcyjne metody szablonowe. Z tak skonstruowanego szkieletu można korzystać przez zdefiniowanie klas potomnych , które wprowadzają własną implementację zachowań określonej aplikacji przez przykrycie odpowiednich metod szablonowych.

wzorce projektowe 40

METODA SZABLONOWA - szczegóły

Struktura wzorca

Wzorzec składa się z co najmniej dwóch klas. Klasa podstawowa AbstractClass się z wykorzystywane w metodzie , definiuje szkielet algorytmu i jest bazą z której korzysta klient. Składa metody szablonowej templateMethod, rozszerzyć oraz z metod prywatnych (lub musi zdefiniować klasę pochodną, która jest publiczna i której klient nie ma możliwości chronionych) method1 oraz method2, które są templateMethod i zawierają domyślną implementację algorytmu. Klient chcący zmienić któryś z kroków algorytmu ConcreteClass metody implementujące kolejne kroki algorytmu.

w której przedefiniuje jedną bądź wszystkie prywatne

Przykład konkretnego zastosowania (implementacji)

Przykładem zastosowania tego wzorca są biblioteki wspomagające automatyzację testów jednostkowych. Biblioteka jUnit definiuje ogólny algorytm wykonywania testów. Składa się on z trzech podstawowych kroków: przygotowania środowiska do wykonania testów, wykonania testów a następnie posprzątania po wykonanych testach. Kroki te reprezentowane są przez metody setUp, runTest oraz tearDown. Wymienione metody wykonywane są w niezmiennej kolejności przez metodę run, której klient nie może zmienić. Dzięki temu, użytkownik nie może zmieniać kolejności podstawowych bloków algorytmu, może jednak nadpisać metody setUp, runTest oraz tearDown, co pozwala mu dostosować testy do swoich potrzeb.

wzorce projektowe 41

METODA SZABLONOWA– zalety i wady

Plusy

● Jednym z najbardziej neutralnych zastosowań wzorca projektowego metody szablonowej jest udostępnianie pustych „punktów zaczepienia” na poziomie nadklasy tylko po to, by programista mógł w niej wstawiać swoją funkcjonalność właśnie za pośrednictwem odpowiednich relacji dziedziczenia.

Minusy

● Stosowanie tego wzorca jest w większości przypadków nieuzasadnione, lepszym rozwiązaniem jest użycie wzorca strategii. W systemach obiektowych stosowanie mechanizmu dziedziczenia do modyfikowania zachowań nadklasy jest nie zalecane.

wzorce projektowe 42

ŁAŃCUCH ZOBOWIAZAŃ/ŁAŃCUCH ODPOWIEDZIALNOŚCI (ang. Chain of Responsibility)

definicja

Wzorzec projektowy, który automatycznie przekazuje odpowiedzialność za wykonanie zadania do następnika, jeżeli obecny obiekt nie potrafi obsłużyć otrzymanego zadania. W przypadku gdy następnik nie istnieje - zadanie zostaje odrzucone. Łańcuch zobowiązań można wyobrazić sobie jako listę obiektów obsługujących, którą przechodzimy dopóki nie znajdziemy obiektu, który będzie w stanie obsłużyć żądane zadanie. Łańcuch zobowiązań prowadzi do utworzenia łańcucha obiektów, które analizując żądanie zapewniają obsługę lub przekazują je dalej. Odpowiedzialność za przetworzenie żądania spada na obiekt, który jest do tego zadania najlepiej przygotowany.

przeznaczenie

Wzorzec znajduje zastosowanie wszędzie tam, gdzie mamy do czynienia z różnymi mechanizmami podobnych żądań, które można zaklasyfikować do różnych kategorii. Dodatkową motywacją do jego użycia są często zmieniające się wymagania., czyli wzorzec łańcucha zobowiązań stosujemy, gdy: ● więcej niż jeden obiekt może obsłużyć żądanie ; ● przesyłamy żądania do jednego z wielu odbiorców bez bezpośredniego specyfikowania odbiorcy; ● zbiór obiektów mogących obsłużyć żądanie jest definiowany automatycznie;

wzorce projektowe 43

ŁAŃCUCH ZOBOWIAZAŃ/ŁAŃCUCH ODPOWIEDZIALNOŚCI - szczegóły

Struktura wzorca

Struktura tego wzorca jest bardzo prosta: obiekty typu Handler są powiązane ze sobą w postaci jednokierunkowej kolejki (albo łańcucha). Nadchodzące od klienta żądanie jest przekazywane wzdłuż tego łańcucha, gdzie każdy obiekt typu Handler ma szansę na ich obsłużenie. Co ważne, obiekty typu Handler są od siebie niezależne, tzn. nie wiedzą o sobie nic (poza abstrakcyjnym wskazaniem na obiekt następnika). UCZESTNICY: Handler - definiuje interfejs do obsługi żądań Concrete Handler - obsługuje jeden rodzaj żądania, pozostałe przekazuje do następnika w łańcuchu, posiada referencję typu Handler do następnika Client - inicjuje przetwarzanie, przekazując żądanie do pierwszego obiektu Handler w łańcuchu

wzorce projektowe 44

Przykład konkretnego zastosowania (implementacji)

Obiekt Inbox wywołuje pierwszy obiekt Filtr w łańcuchu. Kolejne filtry przekazują sobie sterowanie Prostym przykładem tego wzorca jest np. mechanizm filtrów obecnych w większości klientów poczty elektronicznej. Wiadomość przychodząca do foldera Inbox jest przesyłana przez łańcuch zdefiniowanych przez użytkownika filtrów: każdy z nich może dokonać pewnej akcji na wiadomości, polegającej na przeniesieniu jej do innego foldera, zmianie jej priorytetu czy usunięciu jej. Każdy filtr podejmuje decyzję (poprzez wywołanie metody isEligible()), czy konkretna wiadomość powinna być przez niego obsłużona, i przekazuje sterowanie dalej.

wzorce projektowe 45

ŁAŃCUCH ZOBOWIAZAŃ/ŁAŃCUCH ODPOWIEDZIALNOŚCI – plusy i minusy

Plusy

● elementy łańcucha mogą być dynamicznie dodawane i usuwane w trakcie działania programu.

● ● zmniejszenie liczby zależności między nadawcą, a odbiorcami, ● implementacja pojedynczej procedury nie musi znać struktury łańcucha oraz innych procedur.

Daje elastyczność w rozdzielaniu odpowiedzialności pomiędzy obiekty.

Minusy

● ● wzorzec nie gwarantuje, że każde żądanie zostanie obsłużone.

śledzenie i debugowanie pracy działania łańcucha może być trudne.

wzorce projektowe 46

STRATEGIA (ang.Strategy)

definicja

Według Bandy Czworga intencją wzorca strategii jest :

algorytmy niezależnie od wykorzystujących je obiektów.”

Szczegółowiej

„Zdefiniowanie rodziny algorytmópw, zastosowanie hermetyzacji dla każdego z nich i stosowanie ich wymiennie. Strategia pozwala zmieniać

: to jeden z czynnościowych wzorców projektowych, który definiuje rodzinę wymiennych algorytmów i kapsułkuje je w postaci klas. Umożliwia wymienne stosowanie każdego z nich w trakcie działania aplikacji niezależnie od korzystających z nich klientów. Hermetyzacja pojedynczego algorytmu przetwarzania w obiekcie strategii zamiast definiowania wszystkich możliwych sposobów przetwarzania w jednym miejscu i wybieraniu odpowiedniego za pomocą długich instrukcji warunkowych. Wzorzec Strategy służy zatem do modelowania algorytmu realizacji pewnej czynności, który może zostać określony i zmieniony w trakcie wykonywania programu.

przeznaczenie

• Często okazuje się, że dziedziczenie jest niewystarczającym sposobem tworzenia oprogramowania. Wtedy z pomocy przychodzi inne techniki projektowania aplikacji np. wzorzec strategii. Strategia definiuje wspólny interfejs dla każdego obsługiwanego algorytmu. Wymusza to na nas stworzenie implementacji obsługiwanych funkcji w klasach dostarczających konkretne algorytmy. Zawsze przed zastosowaniem dziedziczenia warto pomyśleć, czy wzorzec strategii nie będzie lepszym rozwiązaniem. Można jej używać gdy: • Potrzebuje się kilku wariantów pewnego algorytmu. • Algorytm powinien kapsułkować i hermetyzować dane o których klient niekoniecznie powinien wiedzieć • Klasa posiada wiele różnych zachowań zaimplementowanych za pomocą drabinki konstrukcji warunkowych. • Powiązane ze sobą klasy różnią się tylko zachowaniem.

wzorce projektowe 47

STRATEGIA- szczegóły

Struktura wzorca

Elementy wzorca: Strategia — interfejs definiujący operacje, które muszą obsługiwać wszystkie dostępne algorytmy. Zakładamy, że wszyscy klienci zainteresowani wykorzystaniem algorytmów będą używać właśnie tego interfejsu. Konkretna strategia zgodnie ze zdefiniowanym interfejsem. użytkownik rodziny algorytmów posiadający referencję do obiektu Strategia. Istotne jest, że obiekty Klient oraz

Strategia współpracują ze sobą w celu wykonania określonego zadania. Klient wykonuje wszystkie ogólne zadania i nadzoruje przepływ sterowania, zaś strategie implementują te części zadania, które można wymieniać.

—implementuje określony algorytm Klient —

Przykłady konkretnych zastosowań (implementacji)

1) Oficjalna wirtualna maszyna Javy HotSpot wykorzystuje wzorzec Strategia w wewnętrznej implementacji mechanizmu odśmiecania pamięci, oferując do wyboru kilka algorytmów różniących się właściwościami. Programista wybiera strategię odśmiecania najlepiej dopasowaną do profilu jego aplikacji.

2) Innym miejscem zastosowania wzorca jest sytuacja, w której poszczególne strategie rozwiązują inny problem. Za ilustrację może posłużyć tutaj sklep internetowy posiadający swoje oddziały w kilku krajach różniących się obowiązującymi w nich przepisami podatkowymi. Klient implementuje podstawową, wspólną dla wszystkich funkcjonalność, zaś operację naliczenia podatku deleguje do strategii zaimplementowanej dla konkretnego kraju.

wzorce projektowe 48

STRATEGIA– zalety i wady

Zalety

● wzorzec pozwala na ścisłe, formalne zdefiniowanie rozszerzalnych rodzin algorytmów dzięki wprowadzeniu interfejsu .

● bazuje na koncepcji kompozycji, a nie na dziedziczeniu — nie ma sztywnego powiązania między algorytmem, a miejscem jego wykorzystania. Może on być wymieniany w trakcie działania programu, ● ● eliminacja instrukcji warunkowych, ● umożliwia wybór implementacji — algorytmy mogą rozwiązywać ten sam problem, lecz różnić się uzyskiwanymi korzyściami (zużycie pamięci, złożoność obliczeniowa, optymalizacja pod kątem pewnych szczególnych przypadków).

możliwość niezależnego testowania klientów i strategii.

wady

● dodatkowy koszt komunikacji między klientem, a strategią (wywołania metod, przekazywanie danych), ● zwiększenie liczby obiektów.

wzorce projektowe 49

ODWIEDZAJĄCY/WIZYTATOR (ang.Visitor)

definicja

Jest to wzorzec projektowy, którego zadaniem jest odseparowanie algorytmu od struktury obiektowej na której operuje. Praktycznym rezultatem tego odseparowania jest możliwość dodawania nowych operacji do aktualnych struktur obiektów bez konieczności ich modyfikacji. We wzorcu projektowym wprowadzony zostaje nowy typ obiektu Wizytator, którego zadaniem jest "odwiedzenie" każdego elementu w danej strukturze obiektów i wykonanie na nim konkretnych działań. Różne implementacje wizytatorów, mogą wykonywać różne zadania, rozszerzając funkcjonalność struktury elementów, bez ich wewnętrznej modyfikacji.

przeznaczenie

Wizytator można stosować, gdy: • Struktura, którą posiadasz składa się z dużej ilości klas obiektów, z różnymi interfejsami, a Ty potrzebujesz wykonać operacje zależne od tych konkretnych klas. • Wiele różnych operacji niepowiązanych ze sobą musi zostać wykonanych na obiektach złożonej struktury obiektowej. • Klasy definiujące strukturę obiektową rzadko się zmieniają, a Ty często potrzebujesz dopisać nowe operacje na tej strukturze.

• W wszelkiego rodzaju statystykach i raportach budowanych na podstawie dużych struktur danych (stabilnych!) .

• W obsłudze zamówień seryjnych .

wzorce projektowe 50

ODWIEDZAJĄCY/WIZYTATOR- szczegóły

Struktura wzorca

Elementy wzorca: Wizytator – deklaruje interfejs dla każdej klasy elementówKonkretnych. WizytatorKonkretny – implementuje interfejsy zadeklarowane przez wizytatora. Element – deklaruje interfejs przyjmij, otrzymującą jako argument wizytatora. ElementKonkretny Struktura – – implementuje operację przyjmij, a także inne swoje działania. posiada swoje elementy, powinna zapewniać odwiedzającemu interfejs umożliwiający odwiedzanie elementów .

wzorce projektowe 51

Przykłady konkretnych zastosowań (implementacji)

Zadanie: Odwiedź wszystkie pola szachownicy ruchem skoczka szachowego, odwiedzając każde pole tylko raz, zaczynając z a) rogu, b) jednego z pól środkowych, c) jednego z pól na brzegu, ale nie rogu.

Rozwiązanie: Osoba (czyli Klient) sterująca skoczkiem, zaczynającym z odpowiedniego miejsca szachownicy (czyli Odwiedzający), wykonuje ruchy skoczkiem po polach szachownicy (czyli Struktura Obiektów). W zależności od pola na których się znajdzie (czyli Elemencie Struktury) może wykonać zaakceptowane kroki – wycofać ruch (brak możliwości ruchu dalej, a są pola jeszcze bez odwiedzin), przejść do kolejnego wolnego pola, zakończyć przejście (wszystkie pola zostały odwiedzone).

wzorce projektowe 52

ODWIEDZAJĄCY/WIZYTATOR– zalety i wady

Zalety

● łatwe dodawanie nowych operacji, ● ● ● dodawanie nowych operacji bez modyfikacji samej struktury danych, kod realizujący operację zostaje skupiony w jednym miejscu, niezależne odwiedzanie całej hierarchii klas, ● kumulowanie stanu

Wady

● załamanie hermetyzacji, ● utrudnione zmiany w strukturze np. dodawanie nowych klas

wzorce projektowe 53

Pamiątka (ang. memento )

Definicja: Wzorzec, którego zadaniem jest zapamiętanie i udostępnienie na zewnątrz wewnętrznego stanu obiektu bez naruszania hermetyzacji. Umożliwia to przywracanie zapamiętanego stanu obiektu.

Potrzeba zaimplementowania takiej funkcjonalności pojawia się dość często. Memento nie ma na celu zarządzania stanem ale tylko umożliwienie bezpiecznego dostępu do niego i równie bezpiecznego odtworzenia.

Wzorzec pamiątki stosujemy gdy: Chcemy przechowywać stany obiektów i mieć możliwość ich przywrócenia w dowolnym momencie; Chcemy zachować hermetyzację obiektu, którego stan ma być zapamiętywany. Pamiątka może zostać wykorzystana w procesorze tekstu do zaimplementowania operacji "Cofnij" oraz "Ponów". Za każdym razem kiedy użytkownik wykonuje jakąś akcję – wprowadza tekst, zmienia wielkość czcionki czy jej kolor – tworzony jest obiekt pamiątki zapamiętujący bieżący stan dokumentu. Gdy użytkownik zleci wycofanie ostatniej operacji, stan dokumentu zostanie odtworzony za pomocą wcześniej zapisanej pamiątki.

Inny przykład zastosowania tego wzorca projektowego to ziarno generatora liczb pseudolosowych czy pojedynczy stan automatu skończonego.

wzorce projektowe 54

Mediator (ang. mediator )

Definicja: to wzorzec, umożliwiający zmniejszenie liczby powiązań między różnymi klasami, poprzez utworzenie mediatora będącego jedyną klasą, która dokładnie zna metody wszystkich innych klas, którymi zarządza. Nie muszą one nic o sobie wiedzieć, jedynie przekazują polecenia mediatorowi, a ten rozsyła je do odpowiednich obiektów.

Zastosowanie: miejscu.

Jest to wzorzec wykorzystywany do skupiania złożonych procedur komunikacji i sterowania w środowisku powiązanych obiektów. Obiekty w systemie zamiast komunikować się między sobą bezpośrednio robią to poprzez klasę Mediatora – nie muszą wtedy wiedzieć o swoim własnym istnieniu bezpośrednio. Wysyłają informację do mediatora, a on przekaże go do obiektu, który ma być celem żądania. Pozwala to na łatwą przyszłą modyfikację aplikacji, ponieważ wszystkie wspólne relacje są w jednym

Obserwator (ang. observer )

Definicja: to wzorzec z rodziny wzorców operacyjnych. Składa się z obiektu, który nazywamy "obiektem obserwowanym" oraz pewnej liczy obiektów obserwujących. Występuje tutaj relacja typu jeden do wielu. Obiekt obserwowany jest zarządcą danych, informuje on wszystkich swoich obserwatorów o zmianach w danych, które zawiera. Jest on jedynym prawowitym właścicielem owych danych. Gdy obserwatorzy dostają informacje, że dane uległy zmianie, pobierają je od obiektu obserwowanego i dokonują aktualizacji w posiadanych przez siebie danych, pod kątem stanu danych obiektu obserwowanego. Obiekt obserwujący sam może zdecydować, czy dalej chce obserwować, ale również obiekt obserwowany może go usunąć z listy obserwatorów. Obserwator nie zna innych obserwujących, są oni niezależni od siebie (jakakolwiek modyfikacja jednego obserwatora nie wpływają na innych). Wzorzec charakteryzuje się łatwością dodawania nowych obserwujących (tworzymy nową klasę, która będzie implementować interfejs obserwator). Wzorzec obserwatora stosujemy, gdy: • Nie chcemy tworzyć skomplikowanych klas, o wielu zadaniach, które zmniejszałyby naszą elastyczność w ich używaniu, • zmiana w jednym obiekcie pociąga za sobą konieczność zmian w pozostałych (nie wiemy ilu) • obiekt, który zmienia stan bez wnikania w to, czym one są.

wzorce projektowe 55

● Wzorce projektowe (design patterns) są to sprawdzone w praktyce rozwiązanie często pojawiających się, powtarzalnych problemów projektowych czyli to rozpowszechnione w społeczności programistów rozwiązanie powszechnego problemu, sytuacji, z którą możemy się spotkać w czasie projektowania aplikacji. ● Czyli:

„Wzorzec projektowy pozwala uczyć się na sukcesach innych zamiast nauki na własnych błędach”

Mark Johnson ● Wzorce projektowe stosowane są w projektach wykorzystujących programowanie obiektowe czyli np. C++ czy tez Pytonie. ● Wartość wzorców projektowych stanowi nie tylko samo rozwiązanie problemu, ale także dokumentacja, która wyjaśnia cel, działanie, zalety danego rozwiązania, co pomaga w łatwiejszym stosowaniu i adaptacji wzorców w danym zastosowaniu.

● Wzorce projektowe w informatyce wywodzą się z wzorców projektowych w architekturze. ● Termin wzorca projektowego został wprowadzony do inżynierii oprogramowania przez Kenta Becka oraz Warda Cunninghama w 198 7 roku. Natomiast w 1995 roku autorami pierwszej szeroko znanej publikacji poświęconej wzorcom w inżynierii oprogramowania byli E. Gamma, R. Helm, R.Johnson i J. Vlissides, znani jako Banda Czterech (Gang of Four) . ● Podzielili oni wzorce na trzy grupy: Wzorce kreacyjne, wzorce strukturalne, wzorce behawioralne (czynnościowe).

wzorce projektowe 56

Liczne pozycje książkowe takie jak:

● Allan Shalloway James R. Trott:

„Projektowanie zorientowane obiektowo. Wzorce projektowe”

● Allen Holub:

„Wzorce projektowe. Analiza kodu sposobem na ich poznanie”

Z których korzystałem przy przygotowywaniu prezentacji, jak i wiele innych taki jak np.: ● Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides:

„Wzorce projektowe. Elementy oprogramowania obiektowego wielokrotnego użytku”

● Elisabeth Freeman, Eric Freeman, Bert Bates, Kathy Sierra:

„Wzorce projektowe. Rusz głową!”

● Bernd Bruegge, Allen H. Dutoit: „ Inżynieria oprogramowania w ujęciu obiektowym. UML, wzorce projektowe i Java” ● John M. Vlissides: „

Pattern Hatching: Design Patterns Applied”

● Joshua Kerievsky:

„Refactoring to Patterns” Szeroko dostępne medium o dużych możliwościach (czytaj Internet) jest też źródłem bardzo dużej ilości wiedzy o wzorcach np.:

http://brasil.cel.agh.edu.pl/~09sbfraczek/wzorce-projektowe-wstep,1,57.html

wzorce projektowe 57

Cała prezentacja i notatka jest dostępna na mojej stronie internetowej: ● pośrednio:

http://student.agh.edu.pl/~piex/ w zakładce do pobierania --> JPO2 --> laborki

● lub pod bezpośrednim linkiem:

http://student.agh.edu.pl/~piex/semestr5/JPO2/laborki/

wzorce projektowe 58