Projektowanie obiektowe Wzorce projektowe Gang of Four Wzorce
Projektowanie obiektowe Wzorce projektowe Gang of Four Wzorce odpowiedzialności 1
Roadmap Singleton Observer Mediator Proxy Flyweight Chain of responsibility 2
Wzorce odpowiedzialności • Udostępniają techniki centralizacji, delegowania i ograniczania odpowiedzialności zwykłych obiektów 3
Singleton • Go. F – wzorzec kreacyjny • Umożliwienie skupienia całej odpowiedzialności w jednej instancji klasy 4
Singleton – problem • Aplikacja potrzebuje dokładnie jednej instancji klasy. • Obiekt ten ma być dostępny globalnie, a jego inicjalizacja z reguły opóźniona do pierwszej próby dostępu. 5
Singleton – rozwiązanie • Wymuszamy określoną liczbę instancji klasy. • Leniwa inicjalizacja. • Dostęp globalny. 6
Singleton – diagram klas 7
Singleton – przykład 8
Singleton – konsekwencje C Istnieje dokładnie jedna instancja klasy singleton C Metoda get. Instance() klasy singleton hermetyzuje politykę tworzenia dla klasy singleton tak, że klasy ją używające nie zależą od szczegółów implementacyjnych tej metody. • Inne klasy, które chcą się odwoływać do jedynej instancji singleton, muszą użyć statycznej metody get. Instance(). D Dziedziczenie po klasie singleton jest niewygodne: D trzeba utworzyć nie prywatny konstruktor, D nie można przesłonić statycznej get. Instance(). 9
Zależności między wzorcami • • Następujące wzorce mogą użyć singletona w swojej implementacji: • abstract factory, • builder, • prototype. Singletony często to obiekty: • facade (jest potrzebny tylko jeden), • state. 10
Observer • Go. F – wzorzec behawioralny • Umożliwia oddzielić obiekt od znajomości obiektów od niego zależnych 11
Observer – problem • Duży monolityczny kod nie skaluje się dobrze, gdy rośną wymagania w stosunku do wizualizacji i monitorowania aplikacji. • Obiekt jest obarczony odpowiedzialnością informowania swoich klientów o zmianach istotnych atrybutów, mimo że to klient „wie”, które atrybuty są dla niego istotne. 12
Observer – rozwiązanie • Struktura: Osłona/Delegacja. • osłona hermetyzuje (enkapsuluje) rdzeń logiki biznesowej • każda delegacja dostarcza konfigurowalną przez użytkownika, opcjonalną funkcjonalność 13
Observer – diagram klas 14
Observer – przykład 15
Observer – konsekwencje C Objekt dostarcza powiadomienia innym obiektom bez świadomości nadawcy i odbiorcy o sobie nawzajem. • Dostarczanie powiadomień może trwać długo. • Ryzyko cyklicznych powiadomień. 16
Zasada hermetyzacji zmienności • Polega na ukryciu za jednolitym interfejsem wielu różnych implementacji. • Pozwala: • wyeliminować powtarzalność kodu, • wykorzystywać różne elementy aplikacji w jednolity sposób. 17
Mediator • Go. F – wzorzec behawioralny • Pozwala skupić odpowiedzialność w jednej klasie, nadzorującej interakcję innych obiektów 18
Mediator – problem • Potrzebujemy zaprojektować komponenty wielokrotnego użytku, ale zależności między fragmentami, które mogą być potencjalnie wielokrotnie używane, wykazuje fenomen „kodu spagetti” . • Złożoność interakcji między obiektami zbliża się do najbardziej skomplikowanego układu. 19
Mediator – rozwiązanie • Wprowadzamy dodatkowy poziom pośredniczący, który hermetyzuje relacje wiele-do-wielu między innymi komponentami • Struktura: Osłona/Delegacja. • • osłona jest obiektem mapującym. • delegacje są sieci współpracujących obiektów Stosujemy „poprawny politycznie” menadżer (tzw. God object) 20
Mediator – diagram klas 21
Mediator – przykład 22
Mediator – konsekwencje C Większość złożoności związanej z zarządzaniem zależnościami jest przesunięte do obiektu mediatora. To ułatwia implementacje i utrzymanie innych obiektów. C Przesunięcie logiki zależności dla innych klas w jednej klasie mediatora ułatwia programistom znalezienie zależności. D Klasy mediatora z reguły nie umożliwiają ponownego użycia, ponieważ kod obsługujący zależności jest specyficzny dla aplikacji. 23
Zależności między wzorcami Mediator • Mediator jest podobny do facade wyławiając funkcjonalność istniejących klas, z tym że mediator jest znany przez klasy podsystemu i wprowadza do niego nową funkcjonalność. • Mediator i observer są rywalizującymi wzorcami: • • observer rozprasza komunikacje, • mediator hermetyzuje komunikacje. Mediator może skorzystać z observera w celu dynamicznej rejestracji i zarządzenia „kolegów”. 24
Proxy • Go. F – wzorzec strukturalny • Pozwala obiektowi działać w imieniu innego obiektu 25
Proxy – problem • Potrzebujemy obsługiwać „zasobo-żerne” obiekty, ale możemy odłożyć ich tworzenie do momentu, gdy będą faktycznie zażądane przez klienta. • Poprawny obiekt z jakiegoś względu nie jest w stanie przeprowadzić zadeklarowanych działań (np. z uwagi długiego czasu ładowania obiektu) 26
Proxy – rozwiązanie • • Wprowadzamy dodatkową warstwę pośredniczącą, która dostarcza dodatkową funkcjonalność: • rozproszoną komunikację • logowanie, rewizje, • „smart-pointer” (sprytny wskaźnik). Struktura: Osłona/Delegacja. 27
Proxy – diagram klas 28
Proxy – przykład 29
Proxy – konsekwencje C Dostęp do klas przez pozostałą część programu jest realizowany przez wirtualne proxy. C Udostępniane objekty są tworzone dopiero, gdy są potrzebne. C Klasy wykorzystujące proxy nie potrzebują wiedzieć, która obsługująca klasa jest załadowana, albo czy taka klasa bądź jej instancja istnieje • Wszystkie klasy inne niż proxy muszą odwoływać się do usług pośrednio przez klasę proxy. (Inaczej usługa może być załadowana zanim będzie potrzebna) 30
Odpowiedzialność Diagram klas z błędami 31
Chain of Responsibiliy • Go. F - wzorzec behawioralny • Umożliwia przekazywanie żądania na coraz wyższe poziomy aż do znalezienia obiektu, który je obsłuży 32
Chain of Responsibiliy – problem • Mamy potencjalnie zmienną liczbę obiektów „obsługujących” bądź „przetwarzających” oraz strumień żądań. Potrzebujemy wydajnie przetworzyć żądania nie tworząc „twardych” zależności i mapowań. 33
Chain of Responsibiliy – rozwiązanie • Stosujemy rekursywną kompozycje. • Jeden-do-jednego agregacja („ma”) na czubku hierarchii dziedziczenia • Tworzymy listę dołączaną zorientowaną-obiektowo 34
Chain of Responsibiliy – diagram klas 35
Chain of Responsibiliy – przykład Java 36
Chain of Responsibiliy – przykład 37
Chain of Responsibiliy – konsekwencje C Pozwala zwolnić kod kliencki z obowiązku „znajomości” klas obiektów docelowych, które obsługują żądane zachowanie. C Uproszczenie kodu po stronie hierarchii obiektów docelowych i po stronie klienta. C Rozproszenie odpowiedzialności. 38
Zależności między wzorcami Chain of responsibility • Chain of responsibility, command, mediator i observer dotyczą rozdzielenia nadawców i odbiorców za pomocą różnych kompromisów. • Chain of responsibility: • może wykorzystywać command do reprezentacji żądań jako obiekty. • jest często stosowany w połączeniu z composite; rodzic komponentu może działać jako jego następca. 39
Flyweight (waga piórkowa) • Go. F – wzorzec strukturalny • Ma na celu skupienie odpowiedzialności w drobnych, współużytkowanych obiektach 40
Flyweight – problem • Zaprojektowanie obiektów, tak aby otrzymać możliwie najniższy poziom „ziarnistości”, dostarcza optymalnej elastyczności, ale może być nie akceptowalne z punktu widzenia wydajności i zużycia pamięci. 41
Flyweight – rozwiązanie • Pozostawiamy w klasie stan niezależny od instancji. • Stan zależny od instancji dostarcza klient. • Stosujemy fabrykę wspomagającą ponowne użycie 42
Flyweight – diagram klas 43
Flyweight – przykład Java String s 1 = "hello"; String s 2 = "hello"; //store in a string pool. String s 3 = new String("hello"); System. out. println(s 1==s 2); //true, share the same memory address System. out. println(s 1==s 3); //false 44
Flyweight – przykład 45
Flyweight – konsekwencje C Korzystanie z współdzielonych obiektów flyweight może drastycznie zredukować liczbę obiektów w pamięci. D Zwiększa się złożoność programu. D Nie jest możliwe rozróżnienie między bytami, a obiektami, które je reprezentują. D Współdzielone obiekty flyweight nie mogą zawierać wskaźników do obiektów rodziców. 46
Zależności między wzorcami Flyweight • Pokazuje jak stworzyć wiele małych obiektów, a facade jeden reprezentujący cały podsystem. • Jest często stosowany w połączeniu z composite, aby zaimplementować współdzielone węzły liście. • Umożliwia współdzielenie symboli terminalnych w abstrakcyjnym drzewie składni interpretera. • Wyjaśnia kiedy i jak obiekty stanu mogą być współdzielone. 47
- Slides: 47