IoC field, setter vs constructor

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,

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
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

edytowany 1x, ostatnio: vpiotr
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

Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
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.

Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
vpiotr
Setter łamie enkapsulację? Oj, to już za wysoki poziom abstrakcji dla mnie. A co do "niepoprawności" wstrzykiwania - to nie tylko ja tak twierdzę - przejrzyj to co załączyłem jako linki. Być może to domyślne podejście w Spring, co nie znaczy że poprawne ("milion much...").
Koziołek
http://koziolekweb.pl/2012/01/20/ekstremalna-obiektowosc-w-praktyce-czesc-9-nie-uzywaj-getterowsetterowwlasnosci/ łamie ponieważ powoduje zmienność obiektu i daje możliwość grzebania mu w bebechach.
vpiotr
Wygląda na to że zbyt mocno generalizujesz, na podstawie jakiegoś wąskiego zakresu zastosowań. Gdy ja się uczyłem OOP to była taka prosta zasada: nie definiować klas (lub obiektów jak kto woli) które nie mają atrybutów lub metod. w C++ dochodzi do tego uszczegółowienie: klasa bez metod to struktura. W Javie jest inaczej? Być może, ale czy aż tak zmieniły się założenia OOP?
Koziołek
Założeniem jest nieujawnianie implementacji. Setter przynajmniej częściowo ją ujawnia. Ogłasza wszem i wobec "potrzebuję A, B i C" by robić swoje. Klient takiego obiektu nagle musi jakoś dostarczyć pewne komponenty. A nie powinien się tym przejmować.Trochę na zasadzie - jedziesz do mechanika i nie obchodzi cię, czy ma on kanał czy podnośnik by zajrzeć pod samochód.
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.

airborn
Mockito i @InjectMock Twoim przyjacielem ;)
NoZi
  • Rejestracja:około 16 lat
  • Ostatnio:około 9 godzin
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


Hate the sin, love the sinner
edytowany 4x, ostatnio: NoZi
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
Koziołek
Moderator
  • Rejestracja:prawie 18 lat
  • Ostatnio:około miesiąc
  • Lokalizacja:Stacktrace
  • Postów:6821
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).


Sięgam tam, gdzie wzrok nie sięga… a tam NullPointerException
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.

Shalom
@mućka_ tylko że z takim podejsciem to mozemy wszystkie biblioteki i frameworki pisać samemu, bo przecież w cudzym kodzie zawsze coś się może wywalić. Ja jednak wychodzę z założenia że skoro tysiace ludzi używają to może błędy są wyłapywane i naprawiane a ja muszę sie martwić o swój kod. A im mniej tego mojego kodu, im bardziej deklaratywny, tym lepiej.
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)