IoC field, setter vs constructor

0

Witam,
Kiedyś korzystałem tylko z field injection i działało. Ostatnio przy okazji pisania testów coraz częściej używam wstrzyknięcia przez konstruktor. Zdarzyło mi się też używać wstrzyknięcia przez setter (uważam je jednak za niewygodne).

Moim zdaniem zaletą wstrzykiwania przez konstuktor jest prostota rozwiązania: wydaje się to po prostu naturalne. W przypadku field podejrzewam, że pod spodem dzieją się cuda z użyciem refleksi (ponieważ wstrzykuje obiekt do prywatnego pola).

Jakiego typu IoC (setter, constructor, field) używacie / kiedy i dlaczego?

Pozdrawiam,

0

Przez pole, bo jest najbardziej "czyste" w kontekście kodu. Nie wprowadza żadnych dodatkowych metod ani konstruktorów które nie są nigdzie uzywane. Kod jest krótszy i łatwiejszy w utrzymaniu. Jeśli chodzi o testy to można zawsze ładować kontekst testowy i tyle.

0

W przypadku IoC wstrzykiwanie przez setter czy konstruktor nie daje większej różnicy.

Wstrzykiwania przez pole bym się wystrzegał, chociaż może w Javie enkapsulacja nie jest ważna ;-)

http://blog.schauderhaft.de/2012/01/01/the-one-correct-way-to-do-dependency-injection/
http://www.petrikainulainen.net/software-development/design/why-i-changed-my-mind-about-field-injection/
http://www.silkdi.com/help/harmful.html

0

Tak mi sie wydaje, ze field injection musi uzywac refleksji, ktora jest metoda pozwalajaca na gwalcenie enkapsulcji. Z drugiej strony czesto konstuktory domyslne sa wymagane, co powoduje, ze w przypadku wstrzykiwania przez konstuktor dostajemy niepotrzebny kod: konstruktor domyslny.

Shalom:
Czy kontekst testowy, o ktorym pisales, nie jest przypadkiem zabawka mocno powiazana ze Springiem? Nie znalazlem odpowiednika dla JEE. Poza tym wydaje mi sie to bardziej pasujace dla testow integracyjnych czy jednostkowych.

Od biedy w JEE moge testowac z uzyciem wbudowanego kontenera (EJB 3.1+) lub narzedzi kontekstowych typu arquillian, jednak jest to znacznie blizsze testom integracyjnym.

http://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/testing.html

0

@vpiotr, nie pisz takich rzeczy.

Kwestia metody

  1. Wstrzyknięcia przez setter/pole na zewnątrz technicznie niczmym się nie różnią. Ustawienie wartości pola następuje PO utworzeniu obiektu.
  2. Wstrzyknięcie przez konstruktor oznacza, że obiekt wstrzykiwany jest dostępny zanim zostanie utworzony obiekt. Czasami może być to przydatne.

Kwestia designu

  1. Nie wstyrzykujemy przez setter, a przez pole. W obu przypadkach użwana jest refleksja. Jednak setter pozwala na "wybebeszenie" obiektu i łamie enkapsulację. Nawet nie robisz tego świadomie, bo używasz metody (zazwyczaj z rozpędu). Dobranie się do prywatnego pola wymaga już trochę kombinowania.
  2. Wstrzyknięcia przez konstruktor są dobre jeżeli:
    a) potrzebujesz zrobić jakąś "magię" w konstruktorze i nie masz obsługi adnotacji @PostConstruct (np. używasz Guice).
    b) masz mało pól (http://koziolekweb.pl/2011/12/19/ekstremalna-obiektowosc-w-praktyce-czesc-7-nie-uzywaj-klas-o-wiecej-niz-dwoch-polach/)
    c) chcesz zaznaczyć, że dane zależności w jakiś sposób są obowiązkowe albo "magia" z ppkt-u a to walidacja.
0

Moim zdaniem field injection jest kiepskie poniewaz nie daje za duzo mozliwosci (latwego) testowania jednostkowego. Trzeba sie babrac z refleksja itp.
Zgadzam sie w 100% ze settery i gettery zaleznosci lamia enkapsulacje, i tez nie lubie. @vpiotr - settery i gettery to tak naprawde nie metody ktora maja logike (a o to chodzi w OOP), tylko dostep do szczegolow implementacji obiektu, co nie jest OOP. Tak, moim zdaniem gettery i settery nie sa OOP, powoduja ze ludzie pisza proceduralny kod.
Staram sie jak moge uzywac constructor injection. Jesli pol/zaleznosci jest za duzo, to znaczy ze klasa robi zbyt wiele. Podzielic na kilka mniejszych, kazde z mniejsza iloscia zaleznosci, i wstrzykiwac je.

0

Generalnie zgadzam się z @mućka. Jeśli bierzemy pod uwagę testy to Field Injection jest tutaj najgorszym rozwiązaniem. Jeśli zaś Setter Injection i jest to zależność wymagana do działania komponentu to dodatkowo można oznaczyć ją @Required(@Autowired) co znowu oznacza związanie ze springiem. Także najlepszym wg. mnie rozwiązaniem jest Conctructor Injection.

plus link ode mnie:
http://martinfowler.com/articles/injection.html#ConstructorVersusSetterInjection

1

@mućka Tetsowanie takie trudne? Faktycznie kiedyś było, ale od tego czasu trochę się zmienia :)
http://docs.mockito.googlecode.com/hg/latest/org/mockito/InjectMocks.html

0

@mućka_ co do testowania to bez przesady. Bierzesz Mockito i masz @InjectMocks, bierzesz TestNG i masz @Inject (bo pod spodem jest Guice). W Unitach i yak trzeba mockować, zatem "magia" DI w wykonaniu frameworku nie będzie bolała.

@NoZi, ale zróbmy to porządnie czyli użyjmy @Inject z JSR-a i problem z wiązaniem do Springa odpada (jest wiązanie do standardu). Konstruktor zazwyczaj jest najlepszy, bo jasno daje znać co jest niezbędne do działania obiektu. Problem (niewielki, acz upierdliwy) to konieczność pisania konstruktora domyślnego, bo frameworki średnio sobie radzą bez niego (nie wszystkie, ale zawsze).

0

Oczywiscie ze jest magia, mocki, sam kontener IoC to magia, i mozna tego uzywac. Ale czasami najprostsze rozwiazania sa najlepsze, a za takie uwazam konstruktor i jego parametry. Kazdy taki @InjectMocks itp. to kolejna rzecz, ktora moze byc zle zrozumiana, sie wywalic itp. etc.
Call me old fashioned, maybe I am.

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