Jak powinno się tworzyć interfejsy i klasę? Car i CarImpl?

0

Hej,
Byłem w projekcie gdzie np. w pakiecie było 10 klas w stylu.

Car.java
CarImpl.java
Boat.java
BoatImpl.java
User.java
UserImpl.java
UserSenderService.java
UserSenderServiceImpl.java

Ten projekt prowadził Lead Developer i taka była konwencja tworzenia klas i tak też robiono. Co Wy o czymś takim myślicie? Chciałbym poznać zdanie innych ludzi, ponieważ sam mam jeszcze małe doświadczenie i staram się kwestionować wiele rzeczy. Dzięki za rady!

3

W jakim celu tworzył on interfejs do każdej klasy?

2

Tworzenie interfejsu i tylko jednej implementacji wygląda na bezsensowne, nawet frameworki rzadko kiedy już wymagają takiego bezsensu. W przytoczonym przez Ciebie przypadku obstawiam, że twórca mocno trzyma się konwencji z tutoriali do Springa.

1

d/d.

Car, Boat i User to typowe encje (nie zagłębiam się jakie encje, bazodanowe czy biznesowe, lub DTO) - a wychodzenie od interfejsu, wzorzec już nieco przestarzały, ale by to go nie przekreślało, dotyczy klas UDOSTĘPNIAJĄCYCH FUNKCJONALNOŚĆ.

0
Patryk27 napisał(a):

W jakim celu tworzył on interfejs do każdej klasy?

No właśnie wydawało mi się to zbyteczne, bo jeżeli jest tylko jedna implementacja to nie powinno się tworzyć interfejsu, ale on miał taki zwyczaj, nie pytałem się go, ani nie kwestionowałem, ponieważ była to korporacja i był trochę zarozumiały i zarazem chamski, więc po prostu to olewałem, więc wolę się tutaj zapytać.

AnyKtokolwiek napisał(a):

d/d.

Car, Boat i User to typowe encje (nie zagłębiam się jakie encje, bazodanowe czy biznesowe, lub DTO) - a wychodzenie od interfejsu, wzorzec już nieco przestarzały, ale by to go nie przekreślało, dotyczy klas UDOSTĘPNIAJĄCYCH FUNKCJONALNOŚĆ.

Zapomniałem dodać także, że było też coś w stylu

UserSenderService.java
UserSenderServiceImpl.java

itd. itd

6

Jeśli nazywasz klasę *Impl, to nie wiesz do czego ona służy.

0

Dzięki za odpowiedź, tak myślałem że jednak coś jest nie tak z tymi jego konwencjami.

13

Prowdopodobnie lead developer nauczył się javy i jej koszmarnych frameworków 15 lat temu. (A wtedy te frameworki były nawet gorsze niż są obecnie).
Od tego czasu nie uczył się już niczego, zresztą po co... skoro wszystko wie i wszystko przecież działa.

Jest jeszcze możliwość (równoległa), że to Cargo cult - po prostu - dziadowie taki pisali (i działało), ojcowie tak pisali ( i działało) to i my tak piszemy (i działa).

1

*Impl do wszystkiego to patologia jeśli masz proste klasy.
Ale mogą być przydatne jeśli chcesz robić unit testy bez automatycznego mockowania (Mockito) i mocki lub konkretniej stuby piszesz sam.
Wtedy dziedziczenie z klasy bazowej "Car" może być trudne lub niemożliwe, zwłaszcza jeśli klasa ma jakieś rzeczy prywatne które robią coś sensownego (metody, delegaty, pola).

4

Zawsze mnie zastanawia dlaczego człowiek zamiast zapytać kolegi z zespołu, woli założyć konto i zapytać na forum :)

1

Ogólnie używanie impl to anty patern. Na stacku znajdziesz pełno odpowiedzi dlaczego.
Przeważnie celem interfejsu jest utworzenie jakiegoś kontraktu, który będą spełniać klasy implementujące. Po co tworzyć jakiś kontrakt jeśli ma go spełniać jedna implementacja...

4
  1. jak wspomnieli koledzy wyżej, tworzenie interfejsu gdy jest jedna implementacja jest raczej bez sensu.
  2. UserImpl CarImpl - te nazwy nic nie mówią, a druga rzecz, pewnie w jednej klasie UserServiceImpl masz wiele metod, które robią wszystko co związane userem. Ja do tego podchodzę inaczej. Zakładając, że mam funkcjonalność dodaj usera, to tworzę klasy(w uproszczeniu): CreateUserRequest (DTO), CreateUserController, UserCreator (service), no i encja User wspólna. Robi się wtedy więcej kodu, ale mam pakiecik od tworzenia nowego użytkownika, pakiecik od deaktywacji użytkownika itd. a nie jeden UserService a w nim niekończąca się lista wstrzykniętych beanów :)
2

Ja w jednej rzeczy się trochę nie zgodzę, w architekturze hexagonalnej są czesto interfejsy z jedną implentacją, ale tam nie ma jakiś ProductDetailsRepository i ProductDetailsRepositoryImpl tylko np. GetProductDetailsPort i GetProductDetailsPostgresAdapter albo GetProductDetailsRestAdapter. Ale to wyjątek od reguły w celu zachowania Dependency Inversion Principle.

2

Ja to nazywam interface obsession i całkiem niedawno musiałem niektórym osobom w zespole wyperswadować takie podejście. Niektórzy po prostu- z wielololetniego przyzwyczajenia- odczuwają dyskomfort jeśli w konstruktorze klasy widzą argumenty nie będące interfejsem. Zamiast spytać samych siebie dla czego tak się czują to z góry zakładają że coś jest nie tak, i przywracają to do stanu "normalności". Po co? Nad tym się nie zastanawiają. Ogólnie to pisząc jakiś serwis który gdzieś wstrzykujemy trzeba się trzymać zasady YAGNI. Oczywiście w ramach rozsądku, bo jeśli pracujemy nad szkieletem nowej funkcjonalności i mamy tylko jedną implementację, oraz wiemy na 100% że w następnym sprincie tych implementacji dojdzie już więcej i będzie trzeba zastosować wzorzec strategia no to wręcz wypadało by zrobić to należycie od początku tak aby podstawy już mieć gotowe.

@scibi92 polemizowałbym. To że arechitektura hexagonalna ma porty i adaptery nie oznacza że każdy musi mieć port lub adapter w nazwie. Moim zdaniem to jest niepotrzebne zaśmiecanie logiki biznsowej technikaliami.

2

To że arechitektura hexagonalna ma porty i adaptery nie oznacza że każdy musi mieć port lub adapter w nazwie.

To jest już szczegół, chodzi bardziej o to że moduł zawierający logikę biznesową nie ma w sobie żadnych zaleznosci do frameworków, ORMów, ElasticSearchów, klientów kafek itp.

0

Dzięki wszystkim bardzo za odpowiedź!

1 użytkowników online, w tym zalogowanych: 0, gości: 1