Pracuję od jakiegoś czasu w projekcie, w którym kiedyś podjęto decyzję, aby tworzyć interfejsy dla serwisów.
Przykład: mamy interfejs HejtoService i dla niego jest implementacja HejtoServiceImpl - i generalnie wszystkie publiczne metody implementacji muszą pokrywać się z tym co jest w interfejsie.
I tak 99% klas ma i zawsze będzie miało tylko jedną implementację - bo zawsze jak zmieniają się wymagania, to modyfikuje się implementację, a nie dopisuje kolejną.

No i później wchodzę do jakiegoś pakietu i mam tam np. 10 plików (5 implementacji i 5 interfejsów) - ciężej cokolwiek znaleźć, ciężej nawigować po drzewku projektu - bo zwyczajnie jest 2x więcej plików.
Dodatkowo chcąc przejść do implementacji danej metody (z miejsca, z którego została użyta), zawsze muszę przejść przez interfejs.
Przykład:
ServiceAImpl -> ServiceB -> ServiceBImpl -> ServiceC -> ServiceCImpl
vs
ServiceA -> ServiceB -> ServiceC
Debugując jest identycznie.

Żebyście mnie nie zrozumieli źle, ja lubię używać interfejsów, tam gdzie faktycznie widzę ich zastosowanie. Np. kiedyś kodowałem jakieś generowanie raportów, wykresów, czy czytanie z pliku - gdzie mamy różny format plików, albo przedział czasowy - i tam interfejsy pasują mi idealnie i widzę ich zastosowanie.

No i mam pytanie, po co tworzyć takie interfejsy? Pytam całkiem poważnie i proszę o proste wyjaśnienie, bo dla mnie nie wprowadzają niczego pozytywnego.

#java #programowanie #kiciochpyta
HmmJakiWybracNick userbar
e87ff900-41a6-4eaa-9dcd-7d4ba416b29f
Bujnik

Imo sporo zależy od konwencji jaką przyjmiecie, dla mnie interfejsy są dużo wygodniejsze, zwłaszcza jeśli faktycznie są tam odnośniki do 'głównych' zadań danego serwisu. Też, jak dokumentuje się wystawiony interfejs, dużo czytelniej jest to zrobić właśnie tu zamiast w implementacji, gdzie masz zaciemnione kodem dodatkowo.


Dodatkowo, nie kusi człowieka aż tak by eksponować jakieś prywatne metodki z implementacji, które powinny prywatne pozostać.


A debugując stawiam po prostu w implu breakpointy i tyle, nie widzę problemu

wombatDaiquiri

@HmmJakiWybracNick żeby można było mockować w testach? Czy w Javie się to jakoś inaczej opierdala niż przez podstawienie innej implementacji?

HmmJakiWybracNick

@wombatDaiquiri Zazwyczaj używa się jakiejś biblioteki np. mockito, więc piszesz

given(hejtoService.xyz()).willReturn("Hejto")

monke

@HmmJakiWybracNick jeśli masz clean architecture to interfejs robi za "most" pomiędzy warstwami i dodatkowo w samym interfejsie powinieneś mieć sam język bez bibliotek charakterystycznych dla platformy.

argonauta

Heh, zależy jak się dogadacie na projekcie, ale są pewne zalety tego podejścia jeżeli faktycznie umiesz w Javę.


Wszystko zależy od tego czy robisz użytek z modyfikatorów dostępu, czy YOLO i wszystko public XD...


Mniemam po sposobie nazewnictwa, że korzystasz że Springa to pa tera:


Załóżmy że masz kontekst zarządzania pracownikami (EmployeeManager), wyliczania wyplat (SalaryCalculator) i totalnie od nich na ten moment niezależny: wysylanie powiadomień (NotificationService).


mamy więc


  1. EmployeeManager z którego korzysta z SalaryCalculator do wyciągania pracowników

  2. NotificationService, który niewykluczone że będzie kiedyś użyty przez jeden z poprzednio wymienionych


Jeżeli zalezy Ci na porządku w projekcie, jeżeli odpowiednio użyjesz modyfikatorów dostępu to będziesz samymi dostępami ograniczał z czego inny developer może korzystać w kontekście na którym pracuje:


com.system.employee.EmloyeeManager (publiczny interfejs)

com.system.employee.impl.EmployeeManagerImpl (package-private klasa @Service)

com.system.salary.SalaryCalculator (publiczny interfejs)

com.system.salary.impl.SalaryCalculatorImpl (paclage-private klasa @Service)

com.system.notification.NotificationService (publiczny interfejs)

com.sysyem.notification.impl.NotificationServiceImpl (package-private klasa @Service)


Jaki jest tego efekt? Z zewnątrz możesz skorzystać TYLKO z interfejsów które możesz użyć poprzez wstrzyknięcie zależności. Dzięki temu "sztywno" ograniczasz burdel na projekcie i ciężko juniorowi coś spierdolić.


Wstrzykasz więc sobie w SalaryCalculatorImpl beana od interfejsu EmployeeManager. W przyszłości może też będziesz chciał wpiąć NotificationService (masz publiczny Interfejs pod to!)


Mało tego: w każdej paczce ".impl" możesz mieć wszystko package-private (na ile framework ci pozwala) i tam już możesz nie robić interfejsów pod serwisy pomocnicze, tylko od razu implementacyjną klasę package private - bo przecież powinny być tylko dostępne dla implementacji serwisu dla którego masz stworzony interfejs paczkę wyżej.


Patrz teraz ile masz spełnionych punktów z SOLIDa dzięki takiemu podejściu.

HmmJakiWybracNick

@argonauta Dokładnie ze springa korzystamy.

Wszystko mamy public, chciałem kiedyś przepchnąć, żeby robić package scope co się tylko da, ale nie przeszło... Czasami nawet są takie kwiatki, że jest np. HejtoService, HejtoServiceImpl i jakiś inny serwis wstrzykuje sobie HejtoServiceImpl - no bo czemu nie, skoro jest public...


Pracuję w dwóch projektach i jeden ma taką bardziej lub mniej poprawną strukturę DDD, w której te interfejsy są w pełni uzasadnione.


Ale pytam właśnie pod kątem tego drugiego, gdzie często Repo, Service, ServiceImpl, Controller i inne duperele są wrzucone w jeden pakiet, wszystko jest publiczne i nie rozumiem po co ten interfejs ( ͠° ͟ʖ ͡°)

argonauta

@HmmJakiWybracNick no to nie ma sensu

Ryba_z_mordom_jenota

Wszystko co mądre już zostało powiedziane. Od siebie dodam że warto używać skrótów klawiszowych. Wtedy nawigacja ogranicza się tylko do klawiatury i można szybko trafić do implementacji lub się cofnąć

HmmJakiWybracNick

@Ryba_z_mordom_jenota Ma to sens. Zawsze klikałem Ctrl + LLP, spróbuję przerzucić się trochę bardziej na klawiaturę. Natomiast i tak sporo korzystam z myszki

mpower

@HmmJakiWybracNick przez większą część mojej kariery uważałem, że interfejsy są niezbędne i to faktycznie jest ten słynny Clean Code. Na starość zrozumiałem jednak, że nie ma jednego, uniwersalnego podejścia do tego czym jest Clean Code. Polecam mocno obejrzeć prezentację Jakuba Pilimona https://www.youtube.com/watch?v=W8gcGmVgWQM. Dość dobrze otwiera oczy na ten temat i ja się obecnie zgadzam w pełni z jego podejściem do tematu.

TryingMyBest

W c++ jest coś takiego jak idiom pimpl. https://en.cppreference.com/w/cpp/language/pimpl Pozwala to uniknąć rekompilacji dużych porcji kodu i pozwala na modyfikacje implementacji w libce która używa pimpl bez utraty kompatybilności binarnej (ABI). Może w Javie jest podobny mechanizm? Albo ktoś kto wymyślił takie podejście pisał w cpp i zostało przyzwyczajenie.

Zaloguj się aby komentować