|
| 1 | +--- |
| 2 | +layout: post |
| 3 | +title: "GRASP" |
| 4 | +date: 2019-10-14 |
| 5 | +categories: ["Zasady projektowe"] |
| 6 | +permalink: /blog/zasady/:title/ |
| 7 | +image: principles/grasp |
| 8 | +description: "Zasady projektowe" |
| 9 | +keywords: "zasady, reguły, obiektowe, solid, grasp, odpowiedzialność, information expert, creator, controller, low coupling, high cohesion, polymorphism, pure fabrication, indirection, protected variations, principle, rules, android, programowanie, programming" |
| 10 | +--- |
| 11 | + |
| 12 | +## Wstęp |
| 13 | +`GRASP` (`General Responsibility Assignment Software Patterns`) jest zbiorem dziewięciu zasad określających zakres odpowiedzialności klas i obiektów w systemie. Ułatwiają zrozumienie struktury i sposobu działania tworzonego projektu obiektowego oraz ogranicza wpływ zmian. Nazwy zasad są umowne i nie są powszechnie używane, a ich realizacja może wynikać ze znanych wzorców obiektowych. Co więcej można powiedzieć, że wzorce projektowe `Gang of Four` są po części konsekwencją zaaplikowania zasad `GRASP`. |
| 14 | + |
| 15 | +## Information Expert |
| 16 | +Podstawowym zadaniem w trakcie tworzenia każdego projektu jest decyzja o przypisaniu danej odpowiedzialności do wybranej klasy. |
| 17 | + |
| 18 | +>**Problem** |
| 19 | +Wybór klasy realizującej wybraną odpowiedzialność. |
| 20 | + |
| 21 | +>**Rozwiązanie** |
| 22 | +Odpowiedzialność powinna zostać oddelegowana do klasy posiadającej wszystkie niezbędne informacje wymagane do realizacji zadania uwzględniając wielkość grafu przejść (zależności). |
| 23 | + |
| 24 | +## Creator |
| 25 | +Właściwe przypisanie odpowiedzialności w zakresie tworzenia obiektów sprawia, że projekt jest czytelniejszy i łatwiej rozwijalny z uwagi na zmniejszenie ilości powiązań między obiektami. Jeśli istnieje kilku kandydatów twórców wówczas może powstać problem decyzyjny. Wyjątkiem od tej reguły może być np. wzorzec `Fabryka`. |
| 26 | + |
| 27 | +>**Problem** |
| 28 | +Wybór klasy `B` odpowiedzialnej za tworzenie innego obiektu klasy `A`. |
| 29 | + |
| 30 | +>**Rozwiązanie** |
| 31 | +Klasa `B` powinna mieć przypisaną odpowiedzialność tworzenia obiektu klasy `A`, gdy `B` agreguje obiekty klasy `A`, `B` rejestruje cykl życia instancji klasy `A`, `B` blisko współpracuje z `A` lub `B` posiada zbiór informacji inicjalizacyjnych wymaganych przy tworzeniu `A`. |
| 32 | + |
| 33 | +## Controller |
| 34 | +Interfejs użytkownika jest odpowiedzialny za interakcję z użytkownikiem poprzez przechwytywanie informacji wejściowych i wyświetlanie stanu. Jednakże z uwagi na oddzielenie widoku od logiki aplikacji część funkcji systemu powinna zostać realizowana przez obiekt kontrolera nie należący do interfejsu użytkownika. Pozwala to prowadzenie architektury aplikacji co jest aplikowane m.in. we wzorcach `MVP` i `MVVM`. |
| 35 | + |
| 36 | +>**Problem** |
| 37 | +Wybór obiektu nie należącego do interfejsu użytkownika, który powinien obsłużyć operację systemu. |
| 38 | + |
| 39 | +>**Rozwiązanie** |
| 40 | +Delegacja odpowiedzialności do klasy, która reprezentuje cały system jako całość (główny obiekt kontrolera, podsystem) lub reprezentuje przypadek użycia systemu z wystąpieniem danej operacji. |
| 41 | + |
| 42 | +## Low Coupling |
| 43 | +Klasa o dużej ilości powiązań jest silnie zależna od innych klas co może skutkować brakiem możliwości ponownego użycia, utrudnić izolacje oraz wymusząc wiele lokalnych zmian wynikających ze zmian klas powiązanych. O powiązaniu klasy `A` i `B` można mówić, gdy `A` ma atrybut typu `B` lub `C` związanego z `B`, `A` wywołuje metody `B`, `A` posiada metodę związaną z `B` lub `A` dziedziczy po `B`. |
| 44 | + |
| 45 | +>**Problem** |
| 46 | +Utrzymanie niskiej ilości powiązań między obiektami umożliwiającej redukcje wpływu zmian na projekt oraz zwiększenie możliwości ponownego wykorzystania obiektów. |
| 47 | + |
| 48 | +>**Rozwiązanie** |
| 49 | +W trakcie przypisywania odpowiedzialności do obiektów należy dążyć do minimalizacji ilości powiązań (w przypadku wyboru alternatywnego). |
| 50 | + |
| 51 | +## High Cohesion |
| 52 | +Klasa powinna być nastawiona na realizację pojedynczej odpowiedzialności, aby uniknąć tworzenie super klasy i zachować wysoką spójność. Część zadań może zostać oddelegowana do innych klas. Szczególnie nie należy łączyć odpowiedzialności różnych warstw aplikacji. Reguła ta zawiera się w zasadzie `Single Responsibility Principle` (`SOLID`). |
| 53 | + |
| 54 | +>**Problem** |
| 55 | +Utrzymanie klasy o pojedynczej odpowiedzialności ułatwiającej modyfikacje kodu. |
| 56 | + |
| 57 | +>**Rozwiązanie** |
| 58 | +Przypisywanie odpowiedzialności powinno dążyć do maksymalizacji spójności klasy (w przypadku wyboru alternatywnego). |
| 59 | + |
| 60 | +## Polymorphism |
| 61 | +Wykorzystanie mechanizmu polimorfizmu jest nieodłącznym elementem tworzenia projektów w programowaniu obiektowym. Pozwala na zachowanie odpowiedniej struktury i hierarchii klas oraz wykorzystanie elementów na kilka różnych sposobów niezależnie od ich właściwych typów. Umożliwia eliminacje wielu instrukcji warunkowych podejmujących decyzję w zależności od konkretnego typu. |
| 62 | + |
| 63 | +>**Problem** |
| 64 | +Obsługa zadań i odpowiedzialności w zależności od typów obiektów. |
| 65 | + |
| 66 | +>**Rozwiązanie** |
| 67 | +Przydział zobowiazań za pomocą polimorfizmu w miejscu gdzie występuje różnica w zachowaniu obiektów. |
| 68 | + |
| 69 | +## Pure Fabrication |
| 70 | +Niektóre zasady `GRASP` w pewnych przypadkach mogą stać ze sobą w sprzeczności (`High Cohesion` i `Low Coupling`) lub wskazywany wariant jest nie do zaakceptowania (`Informator Expert`). Wówczas powstaje problem decyzyjny o obarczeniu obiektu odpowiedzialnością łamiąc jak najmniejszą ilość zasad znajdując złoty środek. Przykładem takiego bytu może być wzorzec `Singleton`. |
| 71 | + |
| 72 | +>**Problem** |
| 73 | +Wybór obiektu do realizacji wybranego zadania przy jednoczesnym zachowaniu wzajemnie wykluczających się reguł. |
| 74 | + |
| 75 | +>**Rozwiązanie** |
| 76 | +Stworzenie nowej klasy pomocniczej nie reprezentującej żadnego problemu domenowego i przypisanie jej zbioru powiązanych wymagań. |
| 77 | + |
| 78 | +## Indirection |
| 79 | +W procesie tworzenia projektu należy dążyć do minimalizacji powiązań obiektów. W szczególności może zachodzić potrzeba eliminacji bezpośrednich zależności między obiektami bez wpływu na sposób działania. W tym celu wymagany jest obiekt pośredni umożliwiający współpracę różnych elementów bez wiedzy o sobie. Przykładem realizacji zasady może być wzorzec `Adapter` i `Fasada`. |
| 80 | + |
| 81 | +>**Problem** |
| 82 | +Przydział zobowiązania w sytuacji, gdy oczekiwane jest uniknięcie bezpośredniego powiązania między obiektami. |
| 83 | + |
| 84 | +>**Rozwiązanie** |
| 85 | +Przypisanie odpowiedzialności do nowego pośredniego obiektu, którego rolą jest dostarczenie komunikacji dla elementów systemu w taki sposób, aby nie były one zależne bezpośrednio od siebie. |
| 86 | + |
| 87 | +## Protected Variations |
| 88 | +W trakcie procesu projektowania i implementacji systemu należy zadbać o możliwie jak najprostszą ewentualną wymiane elementów systemu na alternatywne. Pozwala to na łatwe dodawanie nowych rozszerzeń i niższy koszt wprowadzanych zmian, modyfikacje implementacji bez oddziaływania na klientów oraz redukcję zależności. Reguła ta zawiera się w zasadzie `Open-Closed Principle` (`SOLID`). |
| 89 | + |
| 90 | +>**Problem** |
| 91 | +Projektowanie obiektów w taki sposób, aby ich modyfikacja nie wywierała szkodliwego wpływu na inne elementy projektu. |
| 92 | + |
| 93 | +>**Rozwiązanie** |
| 94 | +Identyfikacja punktów przewidywanych różnic i niestabilności oraz przypisanie odpowiedzialności do wspólnego stabilnego interfejsu odwołującego się do konkretnych implementacji. |
0 commit comments