Witaj Gościu! ( Zaloguj | Rejestruj )

Forum PHP.pl

> Współpraca Entity
athabus
post 4.06.2018, 14:39:05
Post #1





Grupa: Zarejestrowani
Postów: 898
Pomógł: 48
Dołączył: 2.11.2005
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Mam takie pytanie teoretyczne, które od czasu do czasu pojawia się w moich projektach. Najlepiej chyba będzie opisać na przykładzie.

Piszę aplikację sportową (konkretnie dla pływaków) we frameworku Symfony i w niej mam między innymi dwa obiekty Entity:
- User
- Interval

Użytkownik ma pewne cechy definiowalne - np. prędkość bazową (dajmy na to 2:00/100m), modyfikatory prędkości (np. gdy ma płetwy to płynie 10s/100m szybciej niż bez etc).

Interwał to cegiełka z której buduję treningi do wykonania. Czyli każdy interwał posiada między innymi:
- dystans do pokonania
- prędkość wyrażoną jako prdkość bazowa +/- x sekund.
- listę modyfikatorów do zastosowania - czyli np. dany interwał użytkownik ma płynąć w płetwach

I teraz dochodzimy do tego co mnie interesuje. Mam konkretny interwał w którym jest płyń z prędkością bazową - 5s oraz użyj płetw. Mam konkretnego użytkownika, dla którego prędkość bazowa to 2:00, a modyfikator płetw daje - 10s. Czyli finalnie ten konkretny użytkownik ma popłynąć ten konkretny interwał w tempie 2:00 (prędkość bazowa użytkownika) - 5s (ustawienie interwału) - 10s (bonus za płetwy) - razem daje 1:45/100m.

Pytanie brzmi - jaki obiekt powinien obliczyć tą konkretną wartość, żeby było prawidłowo i zgodnie ze sztuką.

Interwał raczej nie powinien wiedzieć o użytkowniku i vice versa. Robienie tych samych obliczeń w 50 miejscach (np. w kontrolerach) jest bez sensu i trudne w utrzymaniu. Osobiście w tym celu stosuję usługę, którą sobie nazwałem WorkoutService i mam tam takie funkcje jak np getIntevalPace.

Zastanawiam się czy to jest dobre rozwiązanie, czy może jakoś inaczej powinienem to ogarniać.

Go to the top of the page
+Quote Post
 
Start new topic
Odpowiedzi
athabus
post 10.06.2018, 15:11:51
Post #2





Grupa: Zarejestrowani
Postów: 898
Pomógł: 48
Dołączył: 2.11.2005
Skąd: Poznań

Ostrzeżenie: (0%)
-----


Crozin tak jak już pisałem Ci na PW, jeszcze raz dzięki za tak rozbudowaną odpowiedź.

Skłoniła mnie ona do przeanalizowania tematu i trochę poczytałem... Szczerze to mam teraz mały maindfuck w głowie.

Zanim zacznę wchodzić w szczegóły tematu to chyba trzeba zacząć od ogółu. Otóż moje podejście do ww klasy chyba wynika z ogólnie błędnego paradygmatu na którym się oparłem. Gdzieś tam w trakcie nauki Symfony natrafiłem na materiały, które być może trochę opacznie zrozumiałem, ale ogólnie zrozumiałem z nich tyle:
- klasy entity to prosta warstwa dostępu do danych, która powinna w zasadzie w 95% mieć gettery/settery + 5% jakiejś bardzo prostej logiki obiektu.
- cała logika biznesowa powinna trafić do bezstanowych klas serwisowych.

Po dyskusji w tym poście zacząłem temat drążyć i faktycznie jest takie podejście - nie jest to mój wymysł (uff) i nazywa się to klasami anemicznymi. Wiele osób jednak krytykuje to podejście jako zaprzeczenie idei obiektywności. I tak zacząłem sobie to przemyśliwać - faktycznie klasie serwisowej bliżej do programowania strukturalnego niż obiektowego. Przy relatywnie małej aplikacji, takiej jak moja jest to nawet dość wygodne podejście - cała logika biznesowa znajduje się w kilku klasach serwisowych - jest to dość łatwe do poprawiania, rozwijania i nie tworzy dużej ilości kodu - jednym słowem nie jest to do końca głupie podejście...

Z drugiej strony jednak faktycznie jest to zaprzeczenie obiektowości - w tym podejściu obiekty są tak na prawdę strukturami danych a nie obiektami.

Ogólnie więc rozumiem w czym jest problem, ale nie wiem jak w praktyce to poprawić. Trochę zaczyna mi się mieszać co powinno być bezstanowym serwisem, a co powinno być rolą obiektu. Czy moje Entity powinny zostać "anemiczną strukturą danych" i powinna pojawić się jeszcze jedna warstwa, czy powinienem dodać logikę do samych klas entity. Załóżmy, że tworzę nową warstwę - to by oznaczało, że każdy istotny obiekt entity powinienem powielić? Przykładowo w moim przypadku powinienem stworzyć kolejną klasę Workout, która w konstruktorze przyjmowała by Entity Workout + serwisy, które są potrzebne do logiki biznesowej?

Przykładowo czy taki obiekt powinien móc sam się zapisać (czyli mieć dostęp do EntityMenagera w Symfony)?

W innej części aplikacji mam np. bardziej rozbudowany serwis służący do generowania komend głosowych - korzysta on z serwisu zewnętrznego do generowania komend głosowych, z serwisu dokonującego tłumaczeń itp. Czy teraz obiekt workout powinien także takie rzeczy robić jak generować pliki dźwiękowe?

Ogólnie mam spory problem aby ogarnąć podział obowiązków w praktycznym przykładzie. Czytając trywialne przykłady omawiające różne wzorce projektowe, gdzie klasy są na 5 linijek, a przykłady mocno uproszczone wszystko wydaje się oczywiste - ale jak trafia na normalną aplikację, to to wszystko przestaje być już oczywiste.

Chętnie bym rozrysował graf zależności w mojej aplikacji jeśli znalazłby się ktoś, kto by poradził jak to wszystko dobrze poukładać i rozrysował jak krowie na rowie, jak to powinno być. Wiem, że nie ma jednego dobrego rozwiązania, ale chętnie bym poznał różnej podejścia. Znalazłby się ktoś chętny do dyskusji w takim temacie?
Go to the top of the page
+Quote Post

Posty w temacie


Reply to this topicStart new topic
1 Użytkowników czyta ten temat (1 Gości i 0 Anonimowych użytkowników)
0 Zarejestrowanych:

 



RSS Wersja Lo-Fi Aktualny czas: 24.04.2024 - 23:06