cz 3 Wzorce projektowe

background image

Wzorce Projektowe

background image

Plan prezentacji

1.

Czego się spodziewałem?

2.

Czym są? Do czego służą?

3.

Ogólny podział wzorców?

4.

Omówienie przykładowych wzorców:

Dekorator

Fasada

Pełnomocnik

Pyłek

Stan

5.

Bibliografia

background image

Wstęp

Czego się spodziewałem?

Jakiejś magii…

Wielkich nowości…

Co spotkałem?

Znajome pomysły…

background image

Czym są wzorce projektowe?

„Wzorzec projektowy pozwala uczyć się na sukcesach

innych zamiast nauki na własnych błędach”

(Mark Johnson)

Sprawdzone rozwiązania

efektywność

Najlepsze projekty

jakość

Dobre praktyki

skalowalność

background image

Czym są wzorce projektowe?

„Opisem komunikujących się obiektów i klas, które są
specjalnie wykonane, aby rozwiązać ogólny problem
przy dokładnie określonym kontekście”

(GangOfFour, 1994)

„Powracającym rozwiązaniem zagadnień projektowych,
z którymi wciąż się spotykamy”

(Alpert, 1994)

„Zbiorem reguł opisujących, w jaki sposób osiągnąć
pewne cele w dziedzinie programowania”

(Pree, 1994)

background image

Czym są wzorce projektowe?

„Każdy wzorzec opisuje problem, który ciągle na nowo

pojawia się w naszym otoczeniu i opisuje rdzeń jego
rozwiązania w taki sposób, że można go używać milion
razy i nigdy w ten sam sposób.”

(Christopher Alexander)

background image

Elementy wzorca

Nazwa wzorca

Odzwierciedla problem, rozwiązanie i konsekwencje
danego wzorca

Problem

Opisuje zagadnienie i kontekst wystąpienia wzorca

Rozwiązanie

Opisuje elementy tworzące projekt, ich relacje,
odpowiedzialności oraz współpracę

Konsekwencje

Rezultaty zastosowania wzorca – korzyści i straty

background image

Po co nam wzorce?

Zapobiegają ponownemu wymyślaniu kodu
zaprojektowanemu już przez kogoś innego

Zmniejszają liczbę popełnionych błędów

Zapewniają kod łatwo rozszerzalny

Ułatwiają zrozumienie kodu

Ułatwiają komunikację w zespole

Nazwa identyfikuje wzorzec

background image

Podział wzorców

Konstrukcyjne

wykorzystuje się je do pozyskania obiektów zamiast
bezpośredniego tworzenia instancji klasy

programy zyskuj

ą

na elastyczności, gdyż można decydować, jaki

typ obiektu ma zostać utworzony w danym przypadku

Strukturalne

pomagają łączyć obiekty w większe struktury

Behawioralne

charakteryzują sposób, w jaki klasy lub obiekty oddziaływują i
dzielą odpowiedzialności

pomagają definiować przepływ danych w złożonym programie

background image

Katalog wzorców

Przeznaczenie

Konstrukcyjne

Strukturalne

Behawioralne

Zakres

Klasa

Metoda wytwórcza

Adapter

Interpreter
Metoda szablonowa

Obiekt

Budowniczy
Fabryka abstrakcyjna
Prototyp
Singleton

Adapter
Most
Kompozyt
Dekorator
Fasada
Pełnomocnik
Pyłek

Łańcuch zobowiązań
Polecenie
Iterator
Mediator
Pamiątka
Obserwator
Stan
Strategie
Odwiedzający

background image

Sposób omawiania

Nazwa

Przeznaczenie

Co robi? Jakich zagadnień projektowych dotyczy?

Uzasadnienie stosowania

Problem projektowy wraz z rozwiązaniem

Stosowalność

Kiedy wybrać dany wzorzec projektowy?

Struktura (uczestnicy, współpraca)

Omówienie uczestników oraz ich współpracy przy pomocy
diagramów

Konsekwencje

Co zyskujemy, a co tracimy wybierając dany wzorzec?

Przykłady zastosowania

background image

Dekorator

Przeznaczenie

dynamicznie dołącza do obiektów dodatkowe
zobowiązania

zapewnia elastyczną alternatywę dla tworzenia
podklas w celu rozszerzania funkcjonalności

background image

Dekorator

Uzasadnienie stosowania

Czasem chcemy dołączyć pewne zobowiązania do
pojedynczego obiektu (nie do całej klasy)

Pakiet narzędziowy do tworzenia interfejsów
użytkownika powinien np. umożliwiać dodanie do
każdego składnika takich elementów jak ramki, czy
paski przewijania

Rozwiązania:

dziedziczenie ramki, dziedziczenie przewijania (statyczne)

zagnieżdżenie obiektów – otoczka = dekorator

background image

Dekorator

Zagnieżdżenie to może być rekurencyjne:

background image

Dekorator

Aby to osiągnąć musimy zbudować strukturę klas:

background image

Dekorator

Stosowalność

aby dynamicznie i w przezroczysty sposób dodawać
zobowiązania do pojedynczych obiektów

w wypadku zobowiązań które mogą być cofnięte

Gdy rozszerzanie przez definiowanie podklas jest
niepraktyczne (dużo niezależnych rozszerzeń które przy
próbie uwzględnienia każdej ich kombinacji prowadzą
do ogromnej liczby podklas)

background image

Dekorator

Struktura

background image

Dekorator

Uczestnicy

Komponent (KomponentWizualny)

Definiuje interfejs obiektów, do których można dynamicznie
dołączać zobowiązania

KomponentKonkretny (WidokTekstowy)

Definiuje obiekt, do którego można dołączać zobowiązania

Dekorator

Zarządza odwołaniem do obiektu Komponent i definiuje
interfejs dopasowany do interfejsu Komponentu

DekoratorKonkretny (DekoratorZRamkami,
DekoratorZSuwakiem)

Dodaje zobowiązania do komponentu

background image

Dekorator

Współpraca

Dekorator przesyła żądania do swojego obiektu
Komponent

Może wykonywać dodatkowe operacje przed lub po
przesłaniu żądania

background image

Dekorator

Konsekwencje

większa elastyczność niż przy stosowaniu statycznego
dziedziczenia

(dodawanie, usuwanie dekoratorów, podwójna ramka)

unikanie przeładowanych właściwościami klas na
szczycie hierarchii

„płać za to, czego potrzebujesz”, zamiast uwzględniać
wszystkie przewidywane własności przy projektowanie klasy
zasadniczej

łatwiejsza rozszerzalność (dodanie dekoratora)

Dekorator i jego komponent nie są identyczne (nie
można polegać na sprawdzaniu identyczności obiektów)

Projekt zawiera wiele małych obiektów różniących się
nie zachowaniem, a sposobem połączenia

może być trudne w zrozumieniu

background image

Dekorator

Przykłady

Pakiety narzędziowe do tworzenie interfejsów
użytkownika

Strumienie

Strumień *strumień = new StrumieńKompresujący(

new ASCII7Strumień(
new StrumieńPlikowy(„nazwaPliku”)));

background image

Fasada

Przeznaczenie

zapewnia jednolity interfejs dla podsystemu o wielu
interfejsach

interfejs wyższego poziomu

background image

Fasada

Uzasadnienie stosowania

Typowym zadaniem projektowym jest sprowadzenie do
minimum zależności i komunikacji między modułami

Możemy to osiągnąć m.in. przez wprowadzenie fasady,
która zapewnia interfejs bardziej ogólny zapewniający
interfejs całego podsystemu

background image

Fasada

Mamy np. środowisko z podsystemem będącym
kompilatorem. Mamy Parser, Analizator,
WęzełProgramu, …

Dla klienta, który pragnie jedynie skompilować kawałek
programu, nie jest to istotne. Potrzebuje on interfejsu
klasy Kompilator, będącego fasadą dla podsystemu

background image

Fasada

background image

Fasada

Stosowalność

zapewnienie prostego interfejsu do złożonego systemu

stosowanie wzorców rozbija systemy na bardzo wiele małych
klas, co powoduje się bardziej nadają się one do
wielokrotnego użytku oraz są prostsze w rozbudowie

rozrastanie się systemu powoduje natomiast, że klientowi
trudniej jest go wykorzystać

fasada zapewnia prosty, funkcjonalny interfejs, wystarczająco
dobry dla większości klientów, który może pozostać stały
nawet jeśli podsystem wewnątrz uległ zmianie

zwiększa przenośność i niezależność podsystemu

umożliwia układanie systemów warstwami (fasada
definiuje punkty wejścia do podsystemu)

background image

Fasada

Struktura

background image

Fasada

Uczestnicy

Fasada (Kompilator)

Wie jakie klasy podsystemu są odpowiedzialne, za spełnienie
żądania

Przekazuje żądania do odpowiednich obiektów systemu

Klasa podsystemu (Parser, Analizator, …)

Implementuje funkcjonalność systemu

Wykonuje pracę przydzieloną przez fasadę

Nie wie nic o fasadzie

background image

Fasada

Współpraca

Klienci komunikują się z podsystemem, wysyłając
żądania do Fasady, która przekazuje żądania do
podsystemu

(może być zmuszona przetłumaczyć swój interfejs na
interfejsy podsystemu)

Klienci korzystający z fasady nie muszą mieć
bezpośredniego dostępu do obiektów jej podsystemu

background image

Fasada

Konsekwencje

Mniejsza liczba obiektów, z którymi klient ma do
czynienia

(łatwość użycia)

Mogą eliminować złożone lub cykliczne zależności
między obiektami systemu

Większa przenośność na inne platformy

(przy jej użyciu jest mniejsze prawdopodobieństwo, że
zmiana w jednym podsystemie spowoduje konieczność
przebudowy pozostałych

background image

Pełnomocnik

Przeznaczenie

zapewnia reprezentanta innego obiektu w celu
sterowania dostępem do obiektu oryginalnego

background image

Pełnomocnik

Uzasadnienie stosowania

Jednym z powodów sterowania dostępem do obiektu jest
np. chęć odłożenia na później tworzenia/inicjowania
tego obiektu

np. wielkie obrazy rastowe w dokumencie

Otwieranie dokumentu powinno być szybkie i dopiero
kiedy obiekty stają się widoczne powinniśmy je
budować…

Powinno być to przezroczyste dla obiektu dokumentu

Dlatego w miejsce rysunku tworzymy Pełnomocnika,
który dopiero buduje obraz na żądanie wyświetlenia go

background image

Pełnomocnik

Pełnomocnik przechowując dodatkowo np. rozmiary
obrazka może spełniać żądania programu formatującego
bez potrzeby sięgania do egzemplarza rysunku

Aby korzystać z tych udogodnień wystarczy do
istniejącej struktury klas dodać pełnomocnika:

background image

Pełnomocnik

background image

Pełnomocnik

Stosowalność

zawsze, gdy potrzeba uniwersalnego sposobu odwołania
do obiektu

(bardziej wyrafinowanego niż zwykły wskaźnik)

np.

Pełnomocnik zdalny

lokalny reprezentant obiektu z innej przestrzeni
adresowej

Pełnomocnik wirtualny

tworzy kosztowne obiekty na żądanie (np.
PełnomocnikRysunku)

Pełnomocnik ochraniający

kontroluje dostęp do obiektu

zapewnia różne prawa dla różnych obiektów

background image

Pełnomocnik

Sprytny wskaźnik

zastępuje zwykły wskaźnik, wykonując dodatkowe akcje
przy dostępie do obiektu, jak:

zliczanie liczby odwołań do obiektu (usuwanie przy
braku odwołań)

Ładowanie trwałych obiektów do pamięci przy
pierwszym odwołaniu

background image

Pełnomocnik

Struktura

background image

Pełnomocnik

Uczestnicy

Pełnomocnik (PełnomocnikRysunku)

Przechowuje odwołanie, umożliwiające mu dostęp do
prawdziwego obiektu

Zapewnia identyczny interfejs z oryginalnym obiektem
(może wystąpić wszędzie tam, gdzie oryginał)

Kontroluje dostęp do obiektu

… (cokolwiek)

Przedmiot (ObiektGraficzny)

Definiuje wspólny interfejs dla PrawdziwegoPrzedmiotu i
Pełnomocnika

PrawdziwyPrzedmiot (Rysunek)

Definiuje dowolny przedmiot

background image

Pełnomocnik

Współpraca

Pełnomocnik jeśli trzeba przekazuje żądania do
PrawdziwegoPrzedmiotu (w zależności od rodzaju
pełnomocnika)

background image

Pełnomocnik

Konsekwencje

dodatkowy poziom pośredniości dostępu do obiektu,
może:

ukryć fakt, że obiekt jest zdalny

wykonywać optymalizacje jak tworzenie obiektu
na żądanie

dodatkowe czynności porządkowe

ukrywanie np. kopiowania-przy-zapisywaniu

odłożenie na później kopiowania obiektu – będzie on
rzeczywiście skopiowany tylko jeśli użytkownika zażąda
operacji modyfikującej kopię

background image

Pyłek

Przeznaczenie

wykorzystuje współdzielenie obiektów, w celu
efektywnej obsługi wielkiej liczby drobnych
obiektów

background image

Pyłek

Uzasadnienie stosowania

Większość edytorów używa obiektów do
przechowywania takich elementów jak tabele, rysunki

Na ogół jednak powstrzymują się od stosowania
obiektów do reprezentacji poszczególnych znaków w
dokumencie, mimo że przyczyniłoby to się do
zwiększenia elastyczności (nowe zestawy znaków,
jednakowe traktowanie znaków i innych obiektów pod
względem formatowania i wypisywania

Przyczyną tego jest koszt pamięciowy takiego
rozwiązania!

Tutaj pojawia się Pyłek

background image

Pyłek

Jest on współdzielonym obiektem, który może być
używany jednocześnie w wielu kontekstach

Działa on jako obiekt niezależny w każdym kontekście

(nie może niczego zakładać o kontekście działania)

Jest nieodróżnialny od egzemplarza obiektu, który nie
jest współdzielony

Edytor może utworzyć Pyłek dla każdej litery alfabetu

Każdy Pyłek przechowuje wtedy tylko kod znaku, jego
miejsce i styl typograficzny natomiast są mu dostarczane
przez algorytmy rozmieszczania i formatowania tekstu

background image

Pyłek

Logiczny punkt widzenia:

1 znak = 1 obiekt

Fizycznie istnieje jednak jeden współdzielony obiekt dla
każdej litery:

background image

Pyłek

Struktura klas takich obiektów wygląda tak:

Stan zewnętrzny musi być przekazywany jako parametr
do niektórych operacji (dotyczących wystąpień znaków
w dokumencie)

background image

Pyłek

Przechowywanie stanu zewnętrznego jest zadaniem
Klienta, może być ono zaimplementowany w postaci
BDrzewa:

Węzły wewnętrzne = zakresy indeksów glifów

Liście = style

background image

Pyłek

Stosowalność

System używa wielkiej liczby obiektów

Koszty pamięciowe są wysokie ze względu na samą
tylko liczbę obiektów

Większość stanu obiektów może być przeniesiona na
zewnątrz

Po usunięciu stanu zewnętrznego wiele grup obiektów
można zastąpić stosunkowo niewielką liczbą
współdzielonych obiektów

Tożsamość obiektów nie jest istotna w systemie

background image

Pyłek

Struktura

background image

Pyłek

Uczestnicy

Pyłek (Glif)

Deklaruje interfejs, przez który pyłki mogą otrzymywać stan
zewnętrzny i działać zgodnie z nim

PyłekKonkretny (Znak)

Implementuje interfejs pyłku i dodaje pamięć do
przechowywania stanu wewnętrznego

Musi dawać się współdzielić (niezależność od kontekstu w
jakim występuje)

FabrykaPyłków

Tworzy obiekty klasy Pyłek i zarządza nimi

Zapewnia właściwe współdzielenie pyłków

Klient

Utrzymuje odwołania do pyłków

Przechowuje stan zewnętrzny pyłków

background image

Pyłek

Współpraca

Stan którego pyłek potrzebuje do działania musi być
scharakteryzowany albo jako wewnętrzny albo
zewnętrzny. Stan zewnętrzny jest dostarczany przez
klienta

Klienci nie powinni bezpośrednio tworzyć egzemplarzy
klasy PyłekKonkretny (otrzymują je z FabrykiPyłków)

background image

Pyłek

Konsekwencje

Zwiększenie czasu wykonywania w związku z
przesyłaniem lub wyliczaniem stanu zewnętrznego

Oszczędność pamięci

Zmniejszenie łącznej liczby egzemplarzy (współdzielenie)

Wielkość stanu wewnętrznego obiektu

Wyliczanie/przechowywanie stanu zewnętrznego

Często łączony z wzorcem Kompozyt w celu przedstawienia
struktury hierarchicznej ze współdzielonymi węzłami/liśćmi

(problem = stan wewnętrzny nie może zawierać wskaźnika do
rodzica; rozwiązanie = rodzic przekazywany jako część stanu
zewnętrznego)

background image

Stan

Przeznaczenie

Umożliwia obiektowi zmianę zachowania, gdy
zmienia się jego stan wewnętrzny

Obiekt wydaje się zmieniać wówczas swoją klasę

background image

Stan

Uzasadnienie stosowania

Rozważmy klasę PołączenieTCP, reprezentującą
połączenie sieciowe:

Ilekroć połączenie zmienia stan, obiekt PołącznieTCP
zmienia swój obiekt-stan => zmienia przez to swoje
zachowanie

background image

Stan

Stosowalność

Zachowanie obiektu zależy od jego stanu, a obiekt musi
zmieniać swoje zachowanie w czasie wykonywania
programu

Operacje zawierają duże, skomplikowane instrukcje
warunkowe, zależne od stanu obiektu

Stan przenosi każde rozgałęzienie warunkowe do
oddzielnej klasy

background image

Stan

Struktura

background image

Stan

Uczestnicy

Kontekst (PołączenieTCP)

Definiuje interfejs dla Klientów

Utrzymuje egzemplarz podklasy StanuKonkretnego,
definiujący bieżący stan

Stan (StanTCP)

Definiuje interfejs do kapsułkowania zachowania związanego
ze stanem Kontekstu

Podklasa StanuKonkretnego (TCPNawiazane)

Każda implementuje zachowanie związane ze stanem
Kontekstu

background image

Stan

Współpraca

Kontekst przekazuje żądania specyficzne dla stanu do
obiektu StanKonkretny

(być może przekazuje również siebie jako parametr)

Klient konfiguruje Kontekst początkowym stanem, a
następnie nie musi zajmować się bezpośrednio
obiektami Stan

O wyborze kolejnego stanu decyduje albo Kontekst,
albo podklasy StanuKonkretnego

background image

Stan

Konsekwencje

Całe zachowanie dotyczące stanu w jednym obiekcie

Dużo większa liczba klas

Zachowanie mniej zwarte – korzystne gdy wiele stanów
(inaczej duże instrukcje warunkowe)

Jawność przejść między stanami

(coś więcej niż tylko przypisanie kilku zmiennych)

Atomowe przejścia między stanami (zmiana 1 zmiennej)

Możliwość współdzielenia obiektów Stan

background image

Stan

Kto definiuje przejścia? (tego nie ustala wzorzec)

bardziej elastyczne wydaje się umożliwienie podklasom
Stanu samodzielnego ustalenia ich następników

wprowadza to niestety zależności implementacyjne (Stany
muszą o sobie wiedzieć), co może prowadzić do problemów
w dużych systemach z wieloma stanami

background image

Stan

Przykłady

Wiele programów do rysowania zapewnia różnorodne
„narzędzia”:

narzędzie do rysowania

narzędzie do zaznaczania

W zależności od tego, które narzędzie jest aktywne
operacje myszką wywołują inne efekty

Można tu zastosować wzorzec Stanu do reprezentacji
wybranego narzędzia

background image

Stan

background image

Bibliografia

Gamma, Helm, Johnson, Vlissides „Wzorce
projektowe”, WNT 2005.


Wyszukiwarka

Podobne podstrony:

więcej podobnych podstron