Observer Design Pattern kilka pytań

Observer Design Pattern kilka pytań
DE
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
  • Postów:1788
0

Ostatnio próbuję swoich sił w refactoringu kodu projektu, z którym borykam się na co dzień. Mam niewielkie doświadczenie (7msc), więc proszę to wziąć pod uwagę gdybyście chcieli coś wytłumaczyć. Słowem wstępu przedstawię klasy biorące udział w rozważaniach i pożądane zachowanie.

SubjctToOrder - klasa reprezentująca powiązanie pomiędzy klientem, a przedmiotem zamówienia rozumianym u nas w systemie jako nieruchomość
Realestate - model reprezentujący nieruchomość
Contact - model reprezentujący klienta
Wall - na wallu są wyświetlane m.in. różne powiadomienia, takie jak zmiana statusy powiązania itp.

W momencie **zmiany statusu **powiązania (SubjctToOrder) powinien zostać ustawiony odpowiedni status klienta (Contact), odpowiedni status nieruchomości (Realestate) oraz dodany post na wallu (Wall).

W momencie usunięcia powiązania sytuacja wygląda trochę inaczej. To co się rożni to ustawiana jest flaga deleted na 1 (SubjectToOrder) oraz jest dodawany inny post na wallu informujący o usunięciu powiązania. Na ten moment dla każdego komunikatu jest klejona oddzielna metoda w modelu Wall. Akcje w Concat i Realestate pozostają takie same, tylko wywoływana jest zmiana statusy na dostępny, ale wciąż jest to zmiana.

Obecnie wszystko jest robione w zakręconej metodzie postSave. W momencie usunięcia wywoływana jest metoda softDelete, która w zasadzie wygląda identycznie jak postSave (co swoją drogą generuje 150 linii zduplikowanego kodu, łamie zasadę SRP i wiele innych).

Jak tak chwilę na to popatrzyłem to przypasował mi do tego Observer Pattern, ale w nim występuje jedna metoda update i po chwili jednak bardziej byłem skłonny ku zaimplementowaniu Event Managera typu SubjectToOrderStatusChanged i SubjectToOrderDeleted.

Pytania:

  1. Jeden ze starszych programistów w odpowiedzi na mój pomysł stwierdził, że wpychanie tutaj Observera znacząco utrudnia debuggowanie i lepiej tego nie robić. Hmm.. jak ktoś używa var_dumpa, zamiast debuggera.. no nie wiem, co o tym myślicie?

  2. Czy powinienem zaimplementować interface Subject i Observer odpowiednio w modelach wyżej wymienionych, czy do tego tworzy się oddzielne klasy i korzystając ze Strategii wywołuje się metody tych modeli zmieniające status w odpowiednich modelach?

  3. Czy faktycznie lepszym rozwiązaniem w obecnej sytuacji będzie oparcie tego na eventach niż na Observer Pattern?

Jestem otwarty na inne pomysły, bo chcę jakoś opanować ten projekt. Na dzień dzisiejszy problemów podobnych do opisanego jest mnóstwo. Konieczne jest wywołanie tysiąca akcji np. w momencie usunięcia transakcji, a wszystko jest robione manualnie w różnych miejscach przez co jest duży bałagan.

Dziękuję za poświęcony czas.

edytowany 4x, ostatnio: Desu
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

Może opisałeś to trochę niedokładnie, ale dla mnie to wygląda trochę dziwnie co chcesz zrobić.
Zarówno Observer jak i Eventy nadają się do sytuacji kiedy pewna akcja ma powodować kaskadę (potencjalnie asynchronicznych przy eventach) akcji w różnych częściach systemu. W szczególnosci w miejscach które nie są znane -> siła Observera i Event Busa jest to że rejestrować się mogą dowolne obiekty i ten kto wysyła notyfikacje o zmianie nie musi w ogóle wiedzieć o tym kto "słucha".

Ale u ciebie nie widzę w ogóle takiej sytuacji. U ciebie widzę że wykonanie akcji ma powodować wywołanie metod z jakiegoś Serwisu który zmodyfikuje Model.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
DE
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
  • Postów:1788
0

Hmm, masz rację. Czyli jest to poprawnie zaimplementowane? Czy jesteś może w stanie stwierdzić z powyższego opisu jak można to usprawnić i czy jest to konieczne?

Jakoś mi nie pasowało to, że to wszystko się przenika i jest upchane w jednej metodzie pod nazwą postSave. Czyli np. ma być wykonane X czynności po zmianie statusu i wszystkie są tam wrzucone do jednego wora. Logika zmiany statusów, usuwanie dokumentów powiązanych, posty na wallu, to wszystko siedzi w postSavie i to nie na zasadzie takiej, że są tam wywoływane metody, które to realizują tylko wpieprzone są ify, tworzenie odpowiednich klas potrzebnych do wykonania danego zadania itp.

W zasadzie nie jesteś w stanie stwierdzić co się dzieje po zmianie statusu bez przebrnięcia przez to spaghetti

edytowany 3x, ostatnio: Desu
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1

Ale to problem jest zupełnie inny i nazywa się dekompozycja :) Trzeba tą metodę rozbić na kawałki, może nawet wydzielić kilka małych serwisów, może opartych o Strategie. Niemniej na pewno zostawiłbym tutaj model "push" a nie kombinował z "pull" przez observera czy eventy.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
DE
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
  • Postów:1788
0

Bomba. Póki co wiem, że dzwonią, ale jeszcze nie wiem gdzie, to co napsałeś bardzo pomogło :)

Zobacz pozostałe 4 komentarze
Shalom
@karolinaa do gównoburzy pierwsza, ale żeby napisać coś mądrego to nie ma komu ;] może @JasnyPatryk coś napisze?
KA
nie napisze, bo mnie nie wymieniłeś :P
KA
zresztą i tak się nie znam zbytnio akurat na tym wiec nwm co bym miała napisać xd
szarotka
a ja nie napiszę, że się przychylam do opinii shaloma, bo będzi,e że na niego lecę czy coś
JasnyPatryk
  • Rejestracja:ponad 9 lat
  • Ostatnio:około 9 lat
  • Postów:42
1
Shalom napisał(a):

Niemniej na pewno zostawiłbym tutaj model "push" a nie kombinował z "pull" przez observera czy eventy.

"pull" byłby bardzo fajny gdyby to były mikroserwisy, coś co zmienia status wysyła notyfikacje a potem coś te notyfikacje konsumuje.

Tutaj rozumiem że jest to monolit, masz giga wielki model i jakiś elseniorrodeveloperro wpadł na pomysł żeby całą logike wrzucić do tego twojego postSave (piszesz w PHP ?) :D:D:D

Problemem jest to że nie powinien to być żaden postSave tylko serwis(w sumie to widzę że nic nowego nie napiszę), a raczej parę serwisów, a to spięte facadą(nudnie).

  1. Jeden ze starszych programistów w odpowiedzi na mój pomysł stwierdził, że wpychanie tutaj Observera znacząco utrudnia debuggowanie i lepiej tego nie robić

To jest akurat biedny argument, to że intellij nie jest sobie w stanie poradzić a asynchronicznymi wywołaniami ma znaczyć nie wszystko powinno iść w jednym wywołaniu ? nie, noo, zamieniasz jeden ból na inny.

  1. Czy powinienem zaimplementować interface Subject i Observer odpowiednio w modelach wyżej wymienionych, czy do tego tworzy się oddzielne klasy i korzystając ze Strategii wywołuje się metody tych modeli zmieniające status w odpowiednich modelach?

overengineering :D Taka (nie lubie tego słowa) logika biznesowa powinna być wykonywana jawnie, potem przyjdzie ktoś nowy i się będzie pół dnia zastanawiał a czemu takie rzeczy się pod spodem dzieją.

W takim typoeo ERPo landzie, sklepałbym to jakoś tak

Kopiuj
class OrderManagmentFacade
{
	updateStatus(AffectedState affectedState){}
}

class AffectedState {
	Realestate realestate;
	Contact contact;
	Wall wall;
}

class Realestate {}

class Contact {}

class Wall {}

I ja domyślam się że chcesz zmienić pół systemu bo Ci się nie podoba (nie hejtuje, taki zapał jest na +), ale takie wprowadzanie jakiś event-busow do istniejącego i dużego systemu to zabójstwo. Zacznij pisać testy, dziel syf na mniejsze serwisy, wymyślaj dobre nazwy - to ważniejsze.

P.S

W zasadzie nie jesteś w stanie stwierdzić co się dzieje po zmianie statusu bez przebrnięcia przez to spaghetti

A byłbyś w stanie to sprawdzić jakby taka zmiana szła jako notyfikacja ? zresztą, co by się stało jakby na takie zdarzenie słuchało dwóch listenerów(dwa listenery ?), to który zapdejtuje dane jest dość niedeterministyczne, mogło by się w twoim systemie wydarzyć coś takiego że ktoś usuwa te połączenie(zdarzenie1 przez listener1), potem ktoś znowu je nawiązuje, ale zdarzenie wysłane jako pierwsze usunięcie zostało obsłużone z opóźnieniem(zdarzenie1 przez listener2) i tak naprawdę zostaje wykonane niejako dwa razy ? wiem że to może brzmieć dość poyebanie. Dodając takie kul ficzery trzeba pamiętać o konsekwencjach.

P.S.2 moje wypowiedzi musisz traktować z większym dystansem, nie mam studiów i słabo całkuje


je suis @niezdecydowany
edytowany 6x, ostatnio: JasnyPatryk
DE
  • Rejestracja:ponad 9 lat
  • Ostatnio:11 miesięcy
  • Postów:1788
0

masz giga wielki model i jakiś elseniorrodeveloperro wpadł na pomysł żeby całą logike wrzucić do tego twojego postSave

Tak, php :)

I ja domyślam się że chcesz zmienić pół systemu bo Ci się nie podoba

To nie tylko chodzi o podobanie. Codziennie tracę kilka h na naprawianie jakiegoś buga, który wynika z tego, że jest taki bajzel i brakuje testów. Naprawię jedną rzecz, to popsuje 10 innych, a o kolejnych 10 dowiem się od klienta. Klasy i metody działają na zasadzie dźwigni w jakiś trybachif($mode == "pdf") elseif ($mode == "jpg") itp. To wziąłem książkę do wzorców i refactoringu, przeczytałem i staram się coś poprawić, bo inni już chyba zwątpili :D

Dzięki za cenne uwagi.

edytowany 2x, ostatnio: Desu
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)