Wątek przeniesiony 2019-02-25 21:56 z przez somekind.

IoC a DI

Odpowiedz Nowy wątek
2019-02-25 21:46
0

Cześć. Zmagam się ze zrozumieniem pojęć i różnic pomiędzy IoC a DI. Nigdy nie przykuwałem do tego uwagi, po prostu wiedziałem jak się powinno pisać kod.
Nie powinienem robić aby jakaś klasa zależała od drugiej, czyli pisać w klasie Test Class class = new Class();, tylko powinienem wstrzykiwać tę klasę do konstruktora klasy Test. Plusy znam, łatwe utrzymanie, można takie klasy testować zmieniając implementacje.

No ale właśnie, wiem jak to się robi, nie wiem co to dokładnie oznacza. Zawsze mi się wydawało, że to co u góry napisałem, to jest wstrzykiwanie zależności. Gdzieś nad tą klasą tworzę obiekt, który wstrzykuje i to jest właśnie Dependency Injection.

Czy Inversion Of Control jest to cały koncept tego tak jakby? Cały zamysł, a DI to jest tak jakby sposób tego zrobienia?

Przemaglowałem już wiele stron zaczynająć od SO, kończąc na jakiś udziwnionych ścianach tekstu, ale nie mogę tego do końca zrozumieć.
Może mnie ktoś oświecić?

Pozostało 580 znaków

2019-02-25 21:53
2

IoC to jest forma DI. DI oznacza, że przez konstruktor wstrzykujesz zależności np:


public final class UserService {

private final UserRepository userRepository;

public UserService(UserRepository userRepository) {
this,userRepository = userRepository;
}

//reszta kodu
}

Teraz możesz po prostu zamiast w mainie tworzyć cały graf zależności (czyli wywoływać new i przekazywać kolejne reference) użyć do tego kontenera IoC, ale idea jest ta sama. Kontener IoC ma swoje plusi i minusy, jak to ze wszystkim ;)
PS
Można też wstrzykiwac np. przez settery, ale to bardzo głupie, więc założ że tylko przez konstruktor :P


Nie pomagam przez PM. Pytania zadaje się na forum.
edytowany 1x, ostatnio: ŁF, 2019-02-28 10:19

Pozostało 580 znaków

2019-02-25 21:56
0

Tak, te wszystkie wstrzykiwania znam.
Czyli załóżmy samo tworzenie obiektu w mainie i przesyłanie go do konstruktora to DI? A zamysł wywalenia new z klasy UserService to jest IoC?

edytowany 1x, ostatnio: ŁF, 2019-02-28 10:18
Nie cytuj całego posta jeśli jest wyżej i odnosisz się co calosci - scibi92 2019-02-25 22:03

Pozostało 580 znaków

2019-02-25 22:04
0

DI to znaczy że dostarczasz z zewnątrz zależności, a kontener IoC oznacza ze oddelegowujesz do tego framework np. Spring-a


Nie pomagam przez PM. Pytania zadaje się na forum.
edytowany 1x, ostatnio: scibi92, 2019-02-25 22:15

Pozostało 580 znaków

2019-02-25 22:10
12
  1. IoC to pewna idea i nie należy jej mylić z Dependency Inection ani z kontenerami IoC. IoC do kontenera IoC ma się tak jak krzesło do krzesła elektrycznego.
  2. IoC mówi tylko o tym, żeby nie wiązać się ze szczegółami implementacji innych modułów, a jedynie z kontraktami jakie wystawiają. Dany moduł powinien skupiać sie na wykonywaniu swoich zadań i nie powinien wiedzieć niczego o innych modułach, poza kontraktem/interfejsem jaki oferują. Możemy dzięki temu podmienić moduły na inne i póki kontrakty są poprawne, wszystko musi działać.
  3. DI to sposób realizacji IoC -> wstrzykujemy do modułów implementacje, z których one, poprzez jasno zdefiniowany interfejs, korzystają. Ale to nie jest jedyne rozwiązanie, jakiś ServiceLocator czy Factory też może być realizacją IoC.
  4. Kontener IoC to jest sposób realizacji DI, gdzie składaniem obiektów i wstrzykiwaniem zależności zajmuje się kontener

Na PW przyjmuje tylko (ciekawe!) zlecenia. Masz problem? Pisz na forum, nie do mnie.
edytowany 2x, ostatnio: Shalom, 2019-02-25 22:11

Pozostało 580 znaków

2019-02-25 22:11
0

Dostarczam z zewnątrz z zależności, czyli przesyłam do konstruktora.

scibi92 napisał(a):

a IoC oznacza ze oddelegowujesz do tego framework np. Spring-a

W tym wypadku nie mam żadnego framework'a, to o co chodzi :D

Pozostało 580 znaków

2019-02-25 22:14
2

Można też wstrzykiwac np. przez settery ale to bardzo głupie

Pozwolę sobie dodać coś od siebie bo scibi podał bardzo skąpą "argumentację" ;) Otóż przy definiowaniu zależności jako parametry konstruktora deklarujemy kontrakt danej klasy. Oznacza to że już na etapie tworzenia instancji obiekt musi posiadać poprawny stan, a my w konstruktorze możemy przeprowadzić niezbędną do tego walidację. Wstrzykiwanie zależności poprzez właściwości niczego nie gwarantuje, a nowo utworzony obiekt będzie miał duże prawdopodobieństwo posiadania niewłaściwego stanu jeśli jakaś zależność nie została wstrzyknięta. Z tego też powodu jeśli tylko możliwe należy tego unikać.


Na każdy złożony problem istnieje rozwiązanie które jest proste, szybkie i błędne.
co oznacza kontrakt danej klasy? jakiś przykład bądź coś, bo Shalom też napisał "IoC mówi tylko o tym, żeby nie wiązać się ze szczegółami implementacji innych modułów, a jedynie z kontraktami jakie wystawiają. " i nie wiem czym są te konrakty. - jajko1233 2019-02-25 22:45
@jajko1233: kontrakt klasy czy też metody definiuje co dana klasa/metoda oczekuje w postaci argumentów, oraz co zwraca lub jakie operacje wykonuje. Dla przykładu kontrakt metody która dodaje dwie liczby może wyglądać tak: "int add(int x, int y)". Dzieki temu wiesz co musisz przekazać, oraz czego się spodziewać w zamian. - Aventus 2019-02-25 22:51
Nie o to mi chodziło, nie wiem czym jest sam kontrakt, kontrakt może być między equals a hashCode i to rozumiem, coś jak umowa, a przy definiowaniu zależności jako parametry konstruktora deklarujemy kontrakt danej klasy. już nie rozumiem. Czy Tobie chodzi o to, że w konstuktorze klasy mamy np. construcotr(Service service) { this.service=service} ? - jajko1233 2019-02-25 22:55
Przecież podałem Ci przykład- nazwa metody, wraz z listą jej parametrów oraz zwracanym typem jest jej kontraktem. Analogicznie, konstruktor klasy wraz z parametrami (w sensie sam "nagłówek" konstruktora) jest kontraktem klasy. Chociaż to akurat uproszczenie, bo kontrakt klasy można też rozumieć jako szersze pojęcie, mianowicie jako zbiór konstruktorów oraz publicznych metod tejże klasy. Natomiast w kontekście tworzenia instancji klasy, to faktycznie sam konstruktor jest jej kontraktem, ponieważ jasno komunikuje wymagane zależności. - Aventus 2019-02-25 23:02

Pozostało 580 znaków

2019-02-25 22:18
0

Przede wszystkim użycie konstruktora oznacza że obiekt jest gotowy od razu do użycia i pozwala uniknąc mutowalności. Jesli współdzielimy referencję np. do jakiegoś serwisu a korzystamy z setterów to ktoś może na chama podmenić implementacje i to rozpropagować dalej.Oczywiście tak na ogół się nie zdarza, ale nie jest to wykluczone.


Nie pomagam przez PM. Pytania zadaje się na forum.
Nie przede wszystkim, a również ;) "użycie konstruktora oznacza że obiekt jest gotowy od razu do użycia" to jest dokładnie to co opisałem wyżej. - Aventus 2019-02-25 22:43
No tak, ale nie napisałes o mutowalności :p - scibi92 2019-02-25 22:44
zawsze można dać konstruktor + wystawić jeszcze setter. Dla odważnych :D - baant 2019-02-28 08:10
Nie jeśli masz pola oznaczone jak final. A ja tak oznaczam :) - scibi92 2019-02-28 08:25
@baant: to jeden z tych momentów zaczynających się od "potrzymaj mi piwo" ;) - Aventus 2019-02-28 09:18

Pozostało 580 znaków

2019-02-25 23:28
4

@jajko1233:

co oznacza kontrakt danej klasy?

Możesz go dla uproszczenia utożsamić z interfejsem klasy która jest twoją zaleznością.
Wyobraź sobie że piszesz system który wczytuje dane skądś i zapisuje je w jakiejś postaci. Jak mogło by to wyglądać?

class Loader{
    private final DataCollector dataCollector;
    private final DataSaver dataSaver;

    public void execute(){
        dataSaver.saveData(dataCollector.collectData());
    }
}

Zauważ że nie interesuje nas tutaj czy DataSaver to jest JSONDataSaver czy CSVDataSaver albo DataBaseDataSaver. Interesuje nas tylko, że obiekt który dostaniemy spełnia pewien kontrakt -> dostaje dane i zapisuje je, w sobie znany sposób.
Analogicznie ten nasz DataCollector może pobierać dane z różnych miejsc, w różny sposób, jest to dla nas obojętne o ile spełnia kontrakt -> pobiera dane i zwraca je w odpowiedniej postaci.

Zauważ ze napisaliśmy właśnie kawałek kodu, który może później działać z obiektami które nie istniały kiedy to pisalismy. Za 10 lat napiszesz sobie QuantumSingularityDataSaver, wrzucisz go tutaj i wszystko będzie nadal działać! Nie musimy tego kodu w ogóle ruszać, bo on w ogóle nie wie nic o żadnych konkretnych implementacjach. Będzie działać dla każdego obiektu który spelnia oczekiwany kontrakt.


Na PW przyjmuje tylko (ciekawe!) zlecenia. Masz problem? Pisz na forum, nie do mnie.
edytowany 2x, ostatnio: Shalom, 2019-02-25 23:29
Już rozumiem, dzięki wielkie! - jajko1233 2019-02-25 23:36

Pozostało 580 znaków

2019-02-26 08:25
2

Tak jak już wyżej zostało podkreślone IoC to ogólna idea, polegająca na odwróceniu kontroli, która jest implementowana na kilka sposobów:

dependency injection zamiast tworzyć obiekt samemu, niech ten obiekt zostanie dostarczony z zewnątrz
dependency inversion zamiast polegać na jakimś interfejsie, to ja zdefiniuje interfejs jaki oczekuje i niech mi dostarczą obiekt który spełnia ten interfejs
events zamiast odpytywać czy stan się zmienił w systemie, niech system mnie poinformuje o zmianie (jedna z implementacji to chociażby wzorzec obserwator)
aspect-oriented programming zamiast wywoływać samemu powtarzający się kod (crosscutting concern), niech to ten powtarzający kod sam się wywoła i nie zawraca mi głowy

kolejność w tabelce jest nieprzypadkowa, im niżej tym więcej kontroli oddajemy na zewnątrz, co jest zwykle wygodne z punktu widzenia programisty, tyle że wtedy w systemie się pojawia magia i skoro oddaliśmy tą kontrolę to ciężej jest zapanować nad systemem.

A nazwa kontener IoC się wzięła właśnie stąd, że zwykle taki kontener umożliwia nie tylko DI ale też zwykle inna implementację IoC chociażby aspekty.


Pozostało 580 znaków

2019-02-26 09:02
1

Nie wiem skąd się nagle wzięło w temacie Aspect oriented Programming, ale warto pamiętać, że to rak. Niektórzy mówią, ze gorszy od GOTO.
Ślepa ścieżka ewolucji programowania obiektowego. Polecam nie zblizać się jesli nie trzeba.
AOP można użyć przy debugowaniu skomplikowanych bugów lub ewentualnie w monitoringu. Pchanie tam czegokolwiek, co jest ważne dla aplikacji (transakcje, security, itp ), to recepta na katastrofę.
Niestety czołowe frameworki javowe tak robią, ale warto chociaż nie dokładać swojego kamyczka.

Alternatywą sensowniejszą dla AOP jest Monada, a w szególności Free Monad.
Problemy łapiemy na etapie kompilacji (a nie w runtime), a do tego możemy łatwo testować zarówno z aspektami, jak i bez.


Bardzo lubie Singletony, dlatego robię po kilka instancji każdego.
edytowany 2x, ostatnio: jarekr000000, 2019-02-26 09:02
Pokaż pozostałe 2 komentarze
No ok, ale nie jestem jak rozumieć komentarz :P Nie zauważyłem zbyt duzo problemów związnych ze stosowaniem aspektów przez Springa, chociaż jeśli to możliwe wole kompozycje - scibi92 2019-02-26 11:56
Z GOTO i zmennymi globalnymi wielu ludzi też nie widzi problemu. - jarekr000000 2019-02-26 11:58
@scibi92: ja komentowałem post, nie Twój komentarz. :) @jarekr000000: problemem nie jest używanie noży tylko krojenie nim swoich palców zamiast chleba. Widziałem milion sposób na zepsucie kodu bez goto, zmiennych globalnych i aspektów. - somekind 2019-02-26 11:59

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

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