Techniki projektowania – wzorce projektowe
PROJEKTOWANIE Stan „posiadania” Problemy do rozwiązania Przypadki użycia Model dziedziny Operacje systemowe Kontrakty dla operacji systemowych Problemy do rozwiązania Zakres odpowiedzialności poszczególnych klas? Współdziałanie (kooperacja) obiektów w celu realizacji warunków zapisanych w kontrakcie 2
DOMAIN DRIVEN DESIGN (W SKRÓCIE DDD) Domain Driven Design jest koncepcją projektowania systemów informatycznych, w której kluczową rolę odgrywa model dziedziny Autorem DDD jest Eric Evans (Domain-Driven Design: Tackling Complexity in the Heart of Software, 2003) W literaturze polskiej funkcjonują następujące tłumaczenia terminu DDD: Projektowanie Zorientowane na Dziedzinę Projektowanie Sterowane Modelem/Dziedziną Koncepcja DDD to zbiór podstawowych zasad, wzorców oraz sprawdzonych praktyk ułatwiających projektowanie systemu Systemy projektowane zgodnie z duchem DDD mają strukturę warstwową 3
PODSTAWOWE ELEMENTY DDD Encja (ang. Entity) Wartość (ang. Value Object) Serwis (ang. Service) Agregat (ang. Aggregate) Repozytorium (ang. Repository) Fabryka (ang. Factory) 4
OBIEKTY ENCYJNE I WARTOŚCI Entity – obiekty identyfikowalne Tożsamość obiektu jest niezależna od jego stanu Obiekt może zmienić stan i nadal będzie postrzegany jako ten sam obiekt Przykłady: Osoba, Rachunek, Produkt Value Object – obiekty nieidentyfikowalne Tożsamość obiektu stanowi jego stan Obiekt po zmianie stanu jest postrzegany już jako inny obiekt Przykłady: Pieniądz, Data, Punkt, Adres 5
AGREGAT – CO TO JEST? Agregat to podzbiór elementów modelu, który stanowi spójną całość w ramach której spełniane są warunki integralności danych W każdym agregacie istnieje dokładnie jeden element zwany korzeniem i pozostałe elementami zwane wewnętrznymi korzeń agregatu agregat 6 element wewnętrzny
AGREGAT – HERMETYZACJA Korzeń agregatu jest dostępny dla świata zewnętrznego, tzn. obiekty spoza agregatu mogą się do niego bezpośrednio odwoływać Obiekty wewnętrzne nie są bezpośrednio dostępne dla świata zewnętrznego Obiekty wewnętrzne mogą się jednak odwoływać do innych korzeni agregatów Dostęp do obiektów wewnętrznych jest możliwy tylko poprzez korzeń agregatu Agregaty nie mogą współdzielić elementów wewnętrznych – dany element (obiekt) może być częścią tylko jednego agregatu 7
AGREGAT – KORZYŚCI Agregat ułatwia zarządzanie cyklem życia obiektów – agregaty są zapisywane, odtwarzane i usuwane jako całość, co sprzyja utrzymaniu integralności danych Agregat chroni swoje obiekty wewnętrzne – żaden obiekt ze świata zewnętrznego nie może wykonać operacji na obiektach wewnętrznych agregatu inaczej niż za pośrednictwem korzenia, dzięki temu istniej możliwość kontroli działań wykonywanych na obiektach wewnętrznych, co również sprzyja utrzymaniu integralności danych 8
IDENTYFIKACJA AGREGATÓW Jeżeli obiekty klasy A mogą wystąpić samodzielnie (tj. bez związku z innymi obiektami), to obiekty klasy A powinny być korzeniami agregatu Jeżeli obiekty klasy B posiadają powiązania tylko z obiektami klasy A, które to są korzeniami agregatu i ponadto obiekty klasy B nie mogą występować samodzielnie (bez powiązania z jakimś obiektem klasy A), to obiekty klasy B powinny wchodzić w skład agregatu zbudowanego wokół obiektów klasy A 9
AGREGAT – PRZYKŁAD Klasy Wydarzenie i Osoba są jedynymi klasami, których obiekty mogą występować samodzielnie → Obiekty klas Wydarzenie i Osoba są korzeniami agregatów Obiekty klasy Alarm mogą być powiązane tylko z obiektami klasy Wydarzenie, nie mogą też pojawić się samodzielnie → obiekty klasy Alarm są elementami wewnętrznymi w agregacie Wydarzenie Obiekty klasy Adres mogą być powiązane tylko z obiektami klasy Osoba, nie mogą też pojawić się samodzielnie → obiekty klasy Adres są elementami wewnętrznymi w agregacie Osoba Obiekty klasy Uczestnictwo bez związków z obiektami klas Osoba i Wydarzenie nic nie znaczą, powinny być zarządzane przez jeden z wcześniej zidentyfikowanych agregatów → obiekty klasy Uczestnictwo będą elementami wewnętrzymi w agregacie Wydarzenie korzeń agregat 10 korzeń
PROBLEM Z DOSTĘPEM DO OBIEKTÓW BIZNESOWYCH Jeśli klient chce wykonać pewną operację na jednym z obiektów biznesowych, to możliwe są następujące scenariusze: Jeśli obiekt biznesowy nie istnieje, klient tworzy taki obiekt i wykonuje na nim operację Jeśli obiekt biznesowy istnieje, klient uzyskuje dostęp do interesującego obiektu i wykonuje na nim operację Scenariusz 1 nie stwarza większych problemów w realizacji, pod warunkiem jednak że klient posiada kompletne dane potrzebne do utworzenia obiektu biznesowego Scenariusz 2 może stanowić problem, w sytuacji dużej liczby obiektów biznesowych Rozwiązanie dla scenariusza 2 polegające na przechowywaniu wszystkich obiektów biznesowych przez klienta zwiększa niestety liczbę powiązań pomiędzy warstwami i tym samym poziom zależności miedzy warstwami 11
PROBLEM Z DOSTĘPEM DO OBIEKTÓW BIZNESOWYCH (2) W wielu systemach informatycznych wymaga się zapisywania stanu systemu w bazie danych po wykonaniu ciągu operacji systemowych i odtworzenia tegoż stanu w przypadku awarii lub w chwili uruchomienia systemu od nowa W wielu systemach informatycznych liczba obiektów biznesowych jest na tyle duża, że nie jest możliwe ich jednoczesne przetwarzanie w pamięci operacyjnej – potrzebna jest baza danych, w której te obiekty są przechowywane i udostępnianie na żądanie Wszystkie powyższe problemy mogą być efektywnie rozwiązane poprzez wprowadzenie repozytoriów obiektów biznesowych 12
REPOZYTORIUM Wzorzec repozytorium umożliwia dostęp do puli obiektów biznesowych ukrywając przed klientem wszelkie mechanizmy dostępu do bazy danych Z punktu widzenia klienta repozytorium może być traktowane jako kolekcja obiektów biznesowych Repozytorium udostępnia swoim klientom operacje zapisu, odczytu, aktualizacji, usuwania oraz wyszukiwania obiektów biznesowych Koncepcja DDD zaleca utworzenie jednego repozytorium dla każdego agregatu 13
REPOZYTORIUM – PRZYKŁAD Repozytorium wydarzeń – obsługuje agregat Wydarzenie, który składa się z następujących klas: Wydarzenie Alarm Uczestnictwo Repozytorium osób – obsługuje agregat Osoba, który składa się z następujących klas: Osoba Adres warstwa logiki biznesowej warstwa infrastruktury 14
SERWIS W myśl koncepcji DDD serwisy to specjalizowane klasy przeznaczone do wykonywania operacji biznesowych, których nie można przypisać do jednego obiektu biznesowego W szerszym znaczeniu serwisem jest również klasa odpowiedzialna za koordynacje działań związanych z wykonywaniem operacji systemowych w ramach jednego przypadku użycia Serwisy nie posiadają wewnętrznego stanu – zwykle tworzone są na potrzeby konkretnego zadania i po jego wykonaniu są usuwane Serwis jest obiektem rozpoczynającym obsługę operacji systemowej 15
warstwa logiki biznesowej warstwa infrastruktury SERWISY – PRZYKŁAD Serwis Wydarzeń – odpowiada za zarządzanie wykonywaniem operacji systemowych związanych wydarzeniami, np.: UtworzWydarzenie() DodajAlarm() DodajUczestnika() Serwis Osób – odpowiada za zarządzanie wykonywaniem operacji systemowych związanych osobami, np. : UtworzOsobe() UsunOsobe() warstwa aplikacji warstwa logiki biznesowej warstwa infrastruktury 16 16
Przykład: Kasa fiskalna Techniki projektowania - wzorce GRASP Przykład: Kasa fiskalna Opis dziedziny problemu System jest przeznaczony do obsługi procesu sprzedaży. Podstawowa funkcjonalność systemu obejmuje takie czynności jak: wprowadzanie kodów towarów kupowanych przez klienta, obliczanie kwoty do zapłaty, obsługa wszystkich rodzajów płatności (m.in. gotówka, karta kredytowa). System powinien współpracować z systemami finansowo-księgowymi. Ze względu na zmieniające się przepisy podatkowe system powinien umożliwiać zmianę reguł obliczania podatków. System musi ponadto utrzymywać aktualną bazę dostępnych towarów
Identyfikacja klas konceptualnych (1) Techniki projektowania - wzorce GRASP Identyfikacja klas konceptualnych (1) Store – reprezentuje sklep. Sklep opisany jest atrybutami oznaczającymi jego nazwę i fizyczną lokalizację (name, address) Register – reprezentuje kasę fiskalną, na której dokonywane są transakcje Cashier – reprezentuje osobę obsługującą kasę fiskalną Customer – reprezentuje klienta dokonującego zakupu
Identyfikacja klas konceptualnych (2) Techniki projektowania - wzorce GRASP Identyfikacja klas konceptualnych (2) ProductCatalog – reprezentuje katalog produktów oferowanych do sprzedaży ProductDescription – reprezentuje opis produktu. Zawiera takie atrybuty jak description (opis produktu) oraz price (cena) Payment – reprezentuje płatność . Zawiera atrybut amountTendered do przechowywania zapłaconej kwoty
Identyfikacja klas konceptualnych (3) Techniki projektowania - wzorce GRASP Identyfikacja klas konceptualnych (3) Sale – reprezentuje bieżącą sprzedaż (i jednocześnie dokument sprzedaży). Zawiera atrybut date do przechowywania daty transakcji oraz atrybut total do przechowywania całkowitej kwoty do zapłaty SaleLineItem – reprezentuje jedną pozycję na dokumencie sprzedaży. Zawiera atrybut quantity do przechowywania ilości zakupionego towaru
Techniki projektowania - wzorce GRASP Model dziedziny
Przypadek użycia Przypadek użycia: Obsługa sprzedaży Techniki projektowania - wzorce GRASP Przypadek użycia Przypadek użycia: Obsługa sprzedaży Wyzwalacz: Klient przychodzi do kasy z produktami, które zamierza kupić Scenariusz główny: Kasjer rozpoczyna nowy proces sprzedaży Kasjer skanuje kod towaru System rejestruje pozycje sprzedaży, wyświetla opis produktu, cenę oraz oblicza kwotę do zapłaty Kroki 2-3 są powtarzane dla wszystkich produktów System wyświetla kwotę do zapłaty Kasjer informuje klienta o kwocie do zapłaty Klient za pośrednictwem kasjera dokonuje płatności System rejestruje płatność
Diagram sekwencji systemowych Techniki projektowania - wzorce GRASP Diagram sekwencji systemowych Główny scenariusz: Kasjer rozpoczyna nowy proces sprzedaży Kasjer skanuje kod towaru System rejestruje pozycje sprzedaży, wyświetla opis produktu, cenę oraz oblicza kwotę do zapłaty Kroki 2-3 są powtarzane dla wszystkich produktów System wyświetla kwotę do zapłaty Kasjer informuje klienta o kwocie do zapłaty Klient za pośrednictwem kasjera dokonuje płatności System rejestruje płatność
Kontrakty dla operacji systemowych (1) Techniki projektowania - wzorce GRASP Kontrakty dla operacji systemowych (1) Operacja: MakeNewSale() Warunki początkowe: Istnieje obiekt r klasy Register Warunki końcowe: Utworzono obiekt s klasy Sale Atrybutowi s.dateTime przypisano bieżącą datę i czas Utworzono związek pomiędzy obiektem s a obiektem r
Kontrakty dla operacji systemowych (2) Techniki projektowania - wzorce GRASP Kontrakty dla operacji systemowych (2) Operacja: EnterItem(itemId, quantity) Warunki początkowe: Istnieje obiekt s klasy Sale oraz obiekt pd klasy ProductDescription Warunki końcowe: Utworzono obiekt sli klasy SaleLineItem Atrybutowi sli.quantity przypisano wartość argumentu quantity Utworzono związek pomiędzy obiektem sli a obiektem s Utworzono związek pomiędzy obiektem sli a obiektem pd
Kontrakty dla operacji systemowych (3) Techniki projektowania - wzorce GRASP Kontrakty dla operacji systemowych (3) Operacja: EndSale() Warunki początkowe: Istnieje obiekt s klasy Sale Warunki końcowe: Atrybutowi s.isComplete przypisano wartość true
Kontrakty dla operacji systemowych (4) Techniki projektowania - wzorce GRASP Kontrakty dla operacji systemowych (4) Operacja: MakePayment(amount) Warunki początkowe: Istnieje obiekt s klasy Sale Warunki końcowe: Utworzono obiekt p klasy Payment Atrybutowi p.amountTendered przypisano wartość argumentu amount Utworzono związek pomiędzy obiektem p a obiektem s
Projektowanie interakcji wg DDD – wskazówki Operacja systemowa trafia do jednego z serwisów Do zadań serwisu należy pobranie z repozytorium obiektu biznesowego, którego dotyczy operacja oraz delegowanie wykonania operacji do tegoż obiektu Jeśli operacja nie może być przypisana do jednego obiektu biznesowego, wówczas serwis wykonuje wszystkie czynności wymagane przez operacje
Diagram sekwencji dla operacji DodajUczestnika() Serwis Wydarzeń znajduje obiekt Wydarzenie w Repozytorium Wydarzeń oraz obiekt Osoba w Repozytorium Osób Wydarzenie tworzy obiekt klasy Uczestnik i dodaje go do swojej listy (DodajUczestnika) Komunikat systemowy DodajUczestnika() jest odbierany przez obiekt Serwis Wydarzeń Serwis Wydarzeń deleguje wykonanie operacji dodania uczestnika do obiektu Wydarzenie przekazując mu obiekt Osoba
Techniki projektowania - wzorce GRASP Projektowanie Stan wyjściowy: Operacje systemowe są specyfikacją zachowania systemu widzianego z poziomu jego klienta (np. interfejsu użytkownika). Kontrakty dla operacji systemowych opisują stan systemu przed i po wykonaniu operacji systemowej Problem do rozwiązania: Jak przypisać odpowiedzialności do poszczególnych klas i zaprojektować interakcje obiektów, aby zrealizować warunki zapisane w kontrakcie?
Techniki projektowania - wzorce GRASP GRASP - General Resposibility Assignment Software Patterns GRASP to zbiór kilku wzorców projektowania obiektowego związanych z przypisywaniem odpowiedzialności do klas. Autorem wzorców GRASP jest Craig Larman Każdy ze wzorców GRASP to rodzaj zalecenia projektowego, którego uwzględnienie z reguły prowadzi do lepszego rozwiązanie problemu
Wzorce GRASP Ekspert (ang. Expert) Kreator (ang. Creator) Techniki projektowania - wzorce GRASP Wzorce GRASP Ekspert (ang. Expert) Kreator (ang. Creator) Kontroler (ang. Contoller) Luźne sprzężenie (ang. Low Coupling) Wysoka spójność (ang. High Cohesion) Pure Fabrication Polimorfizm (ang. Polimorphism)
Techniki projektowania - wzorce GRASP Wzorce GRASP - Kreator Problem: Która klasa powinna być odpowiedzialna za tworzenie nowych instancji danej klasy? Rozwiązanie: Przypisz klasie B odpowiedzialność tworzenia nowych instancji klasy A, jeśli zachodzi jeden lub kilka z poniższych warunków: Klasa B zawiera (agreguje) obiekty klasy A Klasa B rejestruje obiekty klasy A Klasa B intensywnie używa obiekty klasy A Klasa B posiada dane niezbędne do zainicjalizowania obiektów klasy A
Techniki projektowania - wzorce GRASP Wzorce GRASP – Kreator Im więcej z powyższych punktów jest spełnione, tym mocniejsze jest uzasadnienie dla wyboru klasy B jako kreatora obiektów klasy A W sytuacji, gdy kilka klas kandyduje do bycia kreatorem obiektów klasy A, wówczas wybieramy te klasę, która spełnia najwięcej z powyższych warunków
Techniki projektowania - wzorce GRASP Kreator - przykład Problem: Która klasa powinna być odpowiedzialna za utworzenie obiektu typu SalesLineItem? Kandydaci: Sale zawiera obiekty typu SalesLineItems używa obiekty typu SalesLineItems posiada niezbędne dane (quantity) do zainicjowania obiekt typu SalesLineItems ProductDescription - jest opisem dla obiektów SalesLineItems model dziedziny (fragment )
Kreator - przykład Rozwiązanie: Techniki projektowania - wzorce GRASP Kreator - przykład Rozwiązanie: Na podstawie wzorca Kreator obiekty klasy SalesLineItem powinny być tworzone przez obiekt klasy Sale
Kreator - przykład Elementy modelu projektowego: Techniki projektowania - wzorce GRASP Kreator - przykład Elementy modelu projektowego: kierunek nawigacji od Register do Sale atrybut currentSale w klasie Register – realizacja związku Register – Sale kierunek nawigacji od Sale do SalesLineItem atrybut lineItems w klasie Sale – realizacja związku Sale - SalesLineItems Model projektowy (fragment)
Techniki projektowania - wzorce GRASP Wzorce GRASP - Ekspert Problem: Jak brzmi najbardziej ogólna zasada przypisywania odpowiedzialności? Której klasie przypisać daną odpowiedzialność? Rozwiązanie: Przypisz odpowiedzialność klasie, która ma niezbędne informacje, aby ją zrealizować
Techniki projektowania - wzorce GRASP Wzorce GRASP - Ekspert Wzorzec Ekspert jest jedną z elementarnych zasad projektowania obiektowego Mimo iż powyższa zasada brzmi jak coś oczywistego, jej zastosowanie może nieraz nastręczać trudności Potencjalne problemy z poprawnym stosowaniem wzorca ekspert wynikają najczęściej z rozproszenia informacji po wielu różnych klasach
Techniki projektowania - wzorce GRASP Wzorce GRASP - Ekspert Do poprawnego zastosowania wzorca Ekspert w przypadku rozproszenia informacji konieczny jest podział odpowiedzialności pomiędzy wszystkie klasy posiadające częściowe informacje Każda z klas posiadających częściowe informacje jest tzw. częściowym ekspertem Innym problemem związanym ze wzorcem Ekspert jest naturalna skłonność do przypisywania odpowiedzialności kierując się zasadą, by klasy systemu informatycznego zachowywały się podobnie jak klasy w świecie rzeczywistym, co nie zawsze jest dobrym rozwiązaniem
Techniki projektowania - wzorce GRASP Ekspert - przykład Problem: Która klasa powinna być odpowiedzialna za obliczenie kwoty do zapłaty Kandydaci: Sale – zawiera atrybut total do przechowywania kwoty do zapłaty SalesLineItem – zawiera atrybut quantity niezbędny do obliczenia kwoty do zapłaty za każdy z produktów z osobna ProductDescription – zawiera atrybut price z bieżącą ceną każdego z produktów model dziedziny (fragment )
Ekspert - przykład Rozwiązanie: Techniki projektowania - wzorce GRASP Ekspert - przykład Rozwiązanie: Klasy SalesLineItem i ProductDescription są częściowymi ekspertami - zawierają jedynie cześć informacji niezbędnej do obliczenia całkowitej kwoty do zapłaty Do obliczenia całkowitej kwoty do zapłaty należy zaprojektować odpowiednią interakcję pomiędzy wszystkimi klasami posiadającymi cząstkową informację
Ekspert - przykład Elementy modelu projektowego: Techniki projektowania - wzorce GRASP Ekspert - przykład Elementy modelu projektowego: kierunek nawigacji od SalesLineItem do ProductDescription atrybut description w klasie SalesLineItem – realizacja związku SalesLineItem - ProductDescription Operacja GetTotal() w klasie Sale Operacja GetSubtotal() w klasie SalesLineItem Operacja GetPrice() w klasie ProductDescription Model projektowy (fragment)
Wzorce GRASP – Kontroler Techniki projektowania - wzorce GRASP Wzorce GRASP – Kontroler Problem: Która klasa spoza interfejsu użytkownika powinna jako pierwsza obsługiwać operacje systemową? Rozwiązanie: Przypisz odpowiedzialność klasie, dla której prawdziwe jest jedno z poniższych stwierdzeń: reprezentuje cały system, podsystem, obiekt leżący najwyżej w hierarchii (ang. root object) reprezentuje przypadek użycia, w którym operacja systemowa ma miejsce
Wzorce GRASP – Kontroler Techniki projektowania - wzorce GRASP Wzorce GRASP – Kontroler Kontroler reprezentujący cały system, podsystem itp. pełni role fasady dla całej warstwy logiki biznesowej Na ogół kontroler nie posiada wystarczającej wiedzy, aby kompletnie obsłużyć żądanie, stąd jego praca polega na znalezieniu odpowiedniego obiektu z warstwy logiki biznesowej i przekazaniu do niego sterowania (delegacja) Kontroler typu fasada stosuje się w niewielkich systemach, gdzie nie ma zbyt wielu operacji systemowych Jeśli w systemie jest dużo operacji systemowych, wówczas stosuje się kontrolery reprezentujące pojedyncze przypadki użycia, bądź też grupujące kilka przypadków użycia
Wzorce GRASP – Kontroler Techniki projektowania - wzorce GRASP Wzorce GRASP – Kontroler Kontrolery reprezentujące przypadki użycia są w istocie w istocie tworami sztucznymi, nie mającymi odpowiednika w dziedzinie problemu Kontrolera GRASP nie należy mylić z kontrolerem ze wzorca Model-Widok- Kontroler, który jest elementem warstwy interfejsu użytkownika Kontroler GRASP należy do warstwy logiki biznesowej (znajduje się na granicy tej warstwy)
ROZWIĄZANIE I – KONTROLER TYPU FASADA Klasy pełniące role kontrolerów Kontroler Zarządzanie wykonywaniem operacji systemowych Przechowywanie i udostępnianie obiektów warstwy biznesowej warstwa aplikacji warstwa logiki biznesowej 47 47
KONTROLER TYPU FASADA – CHARAKTERYSTYKA Kontroler reprezentujący cały system, podsystem itp. pełni role fasady dla całej warstwy logiki biznesowej W zakresie odpowiedzialności kontrolera typu fasada leży: koordynacja działań związanych z wykonywaniem operacji systemowych przechowywanie i udostępnianie obiektów warstwy logiki biznesowej Kontroler typu fasada stosuje się w niewielkich systemach, gdzie nie ma zbyt wielu operacji systemowych 48
ROZWIĄZANIE II – KONTROLER TYPU PRZYPADEK UŻYCIA Klasy pełniące role kontrolerów Kontroler Zarządzanie wykonywaniem operacji systemowych Repozytorium Przechowywanie i udostępnianie obiektów warstwy biznesowej warstwa aplikacji warstwa logiki biznesowej warstwa infrastruktury 49 49 49
KONTROLER TYPU PRZYPADEK UŻYCIA - CHARAKTERYSTYKA W zakresie odpowiedzialności kontrolera leży koordynacja działań związanych z wykonywaniem operacji systemowych Klasa Repozytorium jest odpowiedzialna za przechowywanie i udostępnianie obiektów warstwy biznesowej Kontrolery reprezentujące pojedyncze przypadki użycia (lub kilka przypadków użycia) stosuje się w bardziej złożonych systemach, gdzie występuje większa liczba operacji systemowych i/lub wymagane jest zapisywanie i odtwarzanie stanu systemu po wykonaniu pewnego ciągu operacji systemowych 50
REPOZYTORIUM Zasada Persistence Ignorance „System należy projektować w sposób niezależny od infrastruktury, w tym od wszystkich mechanizmów dostępu do danych” Cała logika związana z dostępem do bazy danych w celu odtworzenia, zapisania lub wyszukania obiektów biznesowych zaszyta jest w Repozytorium Z punktu widzenia warstwy logiki biznesowej Repozytorium pełni rolę kolekcji obiektów biznesowych 51
REPOZYTORIUM – PRZYKŁAD Repozytorium wydarzeń Wydarzenie Alarm Uczestnictwo Repozytorium osób Osoba Adres 52
Techniki projektowania - wzorce GRASP Kontroler - przykład Problem: Która klasa jako pierwsza obsługuje operacje systemowe takie jak: MakeNewSale(), EnterItem(), EndSale(), MakePayment()? Kandydaci: Store - reprezentuje cały system Register - reprezentuje podsystem ProcessSaleHandler – klasa utworzona specjalnie w tym celu model dziedziny (fragment)
Techniki projektowania - wzorce GRASP Kontroler - przykład Rozwiązanie 1: funkcje kontrolera pełni klasa Register. Jest to kontroler typu fasada - stosuje się w sytuacji, gdy liczba operacji systemowych jest nieduża Rozwiązanie 2: funkcje kontrolera pełni specjalnie w tym celu utworzona klasa ProcessSaleHandler. Jest to kontroler typu przypadek użycia - stosuje się w sytuacji, gdy liczba operacji systemowych jest znaczna Odrzucono klasę Store jako kandydat na kontroler ze względu na to, że klasa Register również reprezentuje system a jest „bliżej” innych klas, z którymi konieczna będzie współpraca Komentarz: Obydwa rozwiązania są do zaakceptowania. Niemniej praktyka pokazuje, że liczba identyfikowanych operacji systemowych w kolejnych iteracjach projektu wzrasta, stąd preferowane są rozwiązania z dedykowanym kontrolerem (rozwiązanie 2)
Kontroler - przykład Elementy modelu projektowego: Techniki projektowania - wzorce GRASP Kontroler - przykład Elementy modelu projektowego: Operacja MakeNewSale() w klasie Register Operacja EnterItem() w klasie Register Operacja MakePayment() w klasie Register Operacja EndSale() w klasie Register Model projektowy (fragment)
Techniki projektowania - wzorce GRASP Sprzężenie Sprzężenie (ang. coupling) – miara wzajemnej zależności obiektów Wysoki poziom sprzężeń: Duża liczba związków między klasami Brak możliwości grupowania klas – wszystkie klasy są ze sobą ściśle powiązane Niski poziom sprzężeń: Stosunkowo niewielka liczba związków między klasami Możliwość grupowania klas ściślej ze sobą powiązanych
Wzorce GRASP - Luźne sprzężenie Techniki projektowania - wzorce GRASP Wzorce GRASP - Luźne sprzężenie Problem: W jaki sposób spowodować, żeby zmiany we fragmencie modelu jak najmniej wpływały na pozostała część modelu? Co należy czynić, aby zwiększyć możliwość ponownego wykorzystania kodu? Rozwiązanie: Przypisuj odpowiedzialności w taki sposób, aby ograniczyć liczbę związków między klasami
Wzorce GRASP - Luźne sprzężenie Techniki projektowania - wzorce GRASP Wzorce GRASP - Luźne sprzężenie Model zawierający dużo związków między klasami charakteryzuje wiele negatywnych cech: zmiany w jednej klasie implikują zmiany w innych klasach problem ze zrozumieniem modelu trudności w ponownym użyciu (wymaga to użycia wszystkich klas powiązanych) Z drugiej strony związki między klasami są nieodłączną cechą każdego modelu obiektowego - umożliwiają realizację zasady podziału odpowiedzialności Postulat luźnych sprzężeń nie sugeruje w żaden sposób usunięcia związków między klasami. Sugeruje jedynie, że jeśli istnieje możliwość zrealizowania określonej funkcjonalności bez zwiększania poziomu zależności, to należy taką opcję wybrać
Luźne sprzężenie - przykład Techniki projektowania - wzorce GRASP Luźne sprzężenie - przykład Problem: Która klasa powinna być odpowiedzialna za utworzenie obiektu typu Payment i powiązanie go z obiektem typu Sale? Zaproponować rozwiązanie w oparciu o zasadę „Luźne sprzężenie” Kandydaci: Register Sale model dziedziny (fragment )
Luźne sprzężenie - przykład Techniki projektowania - wzorce GRASP Luźne sprzężenie - przykład nowy związek Rozwiązanie 1: Klasa Register jest odpowiedzialna za utworzenie obiektu klasy Payment (zastosowano wzorzec Kreator - w świecie rzeczywistym kasa fiskalna rejestruje płatności) Klasa Register odpowiada za utworzenie powiązania pomiędzy obiektem klasy Sale i obiektem klasy Payment (metoda AddPayment()) Wniosek: Rozwiązanie 1 zwiększa liczbę związków między klasami - powstał nowy związek pomiędzy klasą Register a klasą Payment
Luźne sprzężenie - przykład Techniki projektowania - wzorce GRASP Luźne sprzężenie - przykład Rozwiązanie 2: (preferowane) Klasa Register deleguje do klasy Sale utworzenie obiektu klasy Payment Klasa Sale odpowiada za utworzenie obiektu klasy Payment i utworzenie powiązania pomiędzy obiektem klasy Sale i nowo utworzonym obiektem klasy Payment Wniosek: Rozwiązanie 2 nie zwiększa liczby związków między klasami - rozwiązanie preferowane z punktu widzenia zasady „Luźne sprzężenie”
Luźne sprzężenie - przykład Techniki projektowania - wzorce GRASP Luźne sprzężenie - przykład Elementy modelu projektowego: kierunek nawigacji od Sale do Payment atrybut payment w klasie Sale – realizacja związku Sales - Payment Operacja MakePayment() w klasie Sale
Techniki projektowania - wzorce GRASP Spójność Spójność (ang. cohession) – miara wzajemnego zintegrowania metod składowych klas Niski poziom spójności: Klasa A wykonuje samodzielnie wszystkie operacje Duża liczba operacji w klasie A Średni poziom spójności Klasa A deleguje odpowiedzialność do innych klas Klasa A koordynuje wszystkie operacje Wysoki poziom spójności Klasa A deleguje odpowiedzialność do innych klas Operacje w klasach pomocniczych również delegują część odpowiedzialności
Wzorce GRASP – Wysoka spójność Techniki projektowania - wzorce GRASP Wzorce GRASP – Wysoka spójność Problem: Jak sprawić, aby klasa była łatwa do zarządzania, zorientowana na jedno określone zadanie, a jej kod był zrozumiały? Rozwiązanie: Przypisz odpowiedzialność w taki sposób, aby spójność była jak największa
Wzorce GRASP – Wysoka spójność Techniki projektowania - wzorce GRASP Wzorce GRASP – Wysoka spójność Klasa, która ma zbyt wiele niezwiązanych ze sobą odpowiedzialności posiada niską spójność (kohezję) Niską kohezją charakteryzuje się również klasa, która co prawda odpowiada za jedno zadanie, ale zadanie to jest mocno skomplikowane i jest realizowane samodzielnie przez jedną klasę Aby poprawić kohezje w tym przypadku należy realizację tego zadania rozłożyć na kilka współpracujących ze sobą klas
Wzorce GRASP – Wysoka spójność Techniki projektowania - wzorce GRASP Wzorce GRASP – Wysoka spójność Klasa o wysokiej spójności to klasa skupiona na realizacji ściśle określonej funkcjonalności, posiłkująca się innymi klasami w sytuacji, gdy nie posiada wystarczających informacji lub realizacja funkcjonalności jest złożonym procesem Klasy o wysokiej kohezji to klasy, które posiadają stosunkowo niewiele metod, metody są ze sobą powiązane, kod metod jest krótki i czytelny, a w sytuacji bardziej złożonej logiki następuje delegacja odpowiedzialności do klas współpracujących
Wysoka spójność- przykład Techniki projektowania - wzorce GRASP Wysoka spójność- przykład Problem: Która klasa powinna być odpowiedzialna za utworzenie obiektu typu Payment i powiązanie go z obiektem typu Sale? Zaproponować rozwiązanie w oparciu o zasadę „Wysoka spójność” Kandydaci: Register Sale model dziedziny (fragment )
Wysoka spójność - przykład Techniki projektowania - wzorce GRASP Wysoka spójność - przykład Rozwiązanie 1: Klasa Register jest odpowiedzialna za utworzenie obiektu klasy Payment (zastosowano wzorzec Kreator - w świecie rzeczywistym kasa fiskalna rejestruje płatności) Klasa Register odpowiada również za utworzenie powiązania pomiędzy obiektem klasy Sale i obiektem klasy Payment (metoda AddPayment()) Wniosek: Rozwiązanie 1 zwiększa zakres odpowiedzialność klasy Register. W tym konkretnym przypadku jest do zaakceptowania, niemniej może prowadzić do obniżenia spójności klasy Register (duża liczba odpowiedzialności)
Wysoka spójność - przykład Techniki projektowania - wzorce GRASP Wysoka spójność - przykład Rozwiązanie 2 (preferowane): Klasa Register deleguje do klasy Sale utworzenie obiektu klasy Payment Klasa Sale odpowiada za utworzenie obiektu klasy Payment i utworzenie powiązania pomiędzy obiektem klasy Sale i nowo utworzonym obiektem klasy Payment Wniosek: Rozwiązanie 2 nie zwiększa zakresu odpowiedzialności klasy Register. Klasa Register deleguje wykonanie określonych czynności do klasy Sale - rozwiązanie preferowane z punktu widzenia zasady „Wysoka spójność”
Realizacja operacji MakeNewSale() Techniki projektowania - wzorce GRASP Realizacja operacji MakeNewSale() Operacja: MakeNewSale() Warunki początkowe: Istnieje obiekt r klasy Register Warunki końcowe: Utworzono obiekt s klasy Sale Atrybutowi s.dateTime przypisano bieżącą datę i czas Utworzono związek pomiędzy obiektem s a obiektem r Kontroler Kreator
Realizacja operacji EnterItem() Techniki projektowania - wzorce GRASP Realizacja operacji EnterItem() Operacja: EnterItem(itemId, quantity) Warunki początkowe: Istnieje obiekt s klasy Sale oraz obiekt pd klasy ProductDescription Warunki końcowe: Utworzono obiekt sli klasy SaleLineItem Atrybutowi sli.quantity przypisano wartość argumentu quantity Utworzono związek pomiędzy obiektem sli a obiektem s Utworzono związek pomiędzy obiektem sli a obiektem pd Kontroler Kreator W obecnej wersji zrezygnowano z klasy Item z modelu dziedziny Ekspert
Realizacja operacji MakePayment() Techniki projektowania - wzorce GRASP Realizacja operacji MakePayment() Operacja: MakePayment(amount) Warunki początkowe: Istnieje obiekt s klasy Sale Warunki końcowe: Utworzono obiekt p klasy Payment Atrybutowi p.amountTendered przypisano wartość argumentu amount Utworzono związek pomiędzy obiektem p a obiektem s Kontroler Kreator
Realizacja operacji EndSale() Techniki projektowania - wzorce GRASP Realizacja operacji EndSale() Operacja: EndSale() Warunki początkowe: Istnieje obiekt s klasy Sale Warunki końcowe: Atrybutowi s.isComplete przypisano wartość true Kontroler Ekspert
Model projektowy – wersja finalna Techniki projektowania - wzorce GRASP Model projektowy – wersja finalna
Techniki projektowania - wzorce GRASP Literatura Craig Larman: Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development