Czy ręczne wstrzykiwanie zależności jest lepszą alternatywą dla kompozycji i polimorfizmu?


13

Po pierwsze, jestem programistą na poziomie podstawowym; W rzeczywistości kończę stopień naukowy AS końcowym projektem zwieńczenia latem. W mojej nowej pracy, gdy nie ma dla mnie żadnego projektu (czekają, aby zapełnić zespół nowymi pracownikami), dostaję książki do czytania i nauki podczas oczekiwania - niektóre podręczniki, inne nie tak bardzo (jak Code Complete). Po przejrzeniu tych książek zwróciłem się do Internetu, aby dowiedzieć się jak najwięcej, i zacząłem uczyć się o SOLID i DI (rozmawialiśmy trochę o zasadzie substytucji Liskova, ale niewiele innych pomysłów SOLID). Tak więc, jak się nauczyłem, usiadłem, aby się lepiej uczyć, i zacząłem pisać kod, aby ręcznie korzystać z DI (nie ma ram DI na komputerach programistycznych).

Rzecz w tym, że kiedy to robię, zauważam, że czuję się znajomo ... i wygląda na to, że bardzo przypomina pracę, którą wykonywałem w przeszłości, używając kompozycji klas abstrakcyjnych z wykorzystaniem polimorfizmu. Czy brakuje mi tutaj większego obrazu? Czy jest coś w DI (przynajmniej ręcznie), co wykracza poza to? Rozumiem możliwość, że konfiguracje spoza kodu niektórych frameworków DI mają wielkie zalety, jeśli chodzi o zmianę rzeczy bez konieczności ponownej kompilacji, ale robiąc to ręcznie, nie jestem pewien, czy jest inaczej niż podano powyżej ... Wgląd w to byłby bardzo pomocny!

Odpowiedzi:


21

Podstawową ideą w DI jest po prostu wypychanie zależności do obiektów, zamiast pozwalania im na pobieranie zależności z zewnątrz. Nazywało się to wcześniej „odwróceniem kontroli”. Pozwala to znacznie lepiej kontrolować zależności, a także - na koniec - pisać kod, który jest łatwy do testowania jednostkowego.

Frameworki DI budują tylko na podstawie tego pomysłu i (częściowo) automatyzują często żmudną część zależności między obiektami okablowania. W przeciwnym razie może to wymagać znacznej ilości kodu w większym projekcie, jeśli zostanie wykonane ręcznie.

Do definiowania zależności, oprócz zewnętrznych plików konfiguracyjnych, można obecnie również używać adnotacji kodu, np. W językach takich jak Java i C #. Mogą przynieść to, co najlepsze z obu światów: zależności okablowania w stylu deklaratywnym, ale bezpośrednio w samym kodzie, do którego logicznie należy. Dla mnie możliwość zmiany zależności bez konieczności ponownej kompilacji nie jest tak cenna, ponieważ rzadko odbywa się to w prawdziwym życiu (oprócz niektórych szczególnych przypadków), ale wprowadza często sztuczny rozdział zależności od klas i obiektów zdefiniowanych w kodzie .

Aby powrócić do twojego tytułowego pytania, DI nie jest alternatywą dla kompozycji ani polimorfizmu; w końcu jest to możliwe dzięki tym dwóm.


1
Dependency Injection (DI) jest formą Inversion of Control (IoC).
Matthew Flynn

@MatthewFlynn, rzeczywiście. Dla odniesienia: martinfowler.com/articles/injection.html
Péter Török

1
To jest moje odniesienie. Mówi o nowych „lekkich kontenerach” wykonujących inwersję kontroli, co było już powszechne, ponieważ nasłuchiwania zdarzeń interfejsu użytkownika były formą IoC. Nazywa obiekt wiążącym, który Spring i inne kontenery IoC robią jako Wstrzykiwanie zależności, aby odróżnić go od innej formy Inwersji kontroli.
Matthew Flynn

Ups - brakowało mi słowa „rzeczywiście”. Myślałem, że mi zaprzeczasz ... Przepraszam.
Matthew Flynn

Twój ostatni akapit sprawia, że ​​czuję się trochę lepiej; przez cały czas, gdy pracowałem nad moim małym projektem edukacyjnym, powtarzałem sobie: „to jest jak polimorfizm…”. Niestety .Net i c # w mojej pracy są strasznie nieaktualne, ale patrząc na to, czy Unity jest wbudowanym frameworkiem c #, o którym mówisz?
Drake Clarris

22

Najlepszy artykuł, jaki kiedykolwiek czytałem na ten temat, to James Shore . Od wieków robię „ DI ręcznie ” jako część abstrakcji i polimorfizmu. Po tym, jak wkroczyłem w świat zawodowy i wciąż słyszałem, jak ten termin się rzuca, miałem duże rozróżnienie między tym, co według mnie powinno oznaczać to słowo, a tym, co w rzeczywistości oznacza:

„Wstrzykiwanie zależności” to termin 25 dolarów za koncepcję 5 centów.

To z postu Shore'a, który wyjaśnił mi wszystko. Na przykład:

Dany

class Engine {public abstract void start()}
class V8 extends Engine {...}
class V6 extends Engine {...}

Zamiast pisać:

class Car
{
    private Engine engine;
    public Car()
    {
        this.engine = new V6();
    }

    public void start()
    {
        this.engine.start();
    }
}

Napisz coś takiego:

class Car
{
    private Engine engine;
    public Car(Engine a)
    {
        this.engine = a;
    }

    public void start()
    {
        this.engine.start();
    }
}

...

Car F = new Car(new V8());

Zapobiega Carto obsłudze przez instancję określonych Engineszczegółów. Samochód potrzebuje tylko silnika, który nie dba o to, o ile ma podstawową funkcjonalność silnika. Oznacza to, że twoja Carklasa nie jest powiązana z konkretną zależnością implementacyjną; jest „wstrzykiwany” gdzie indziej, potencjalnie w czasie wykonywania.

Ten konkretny przykład Car używa podtypu DI zwanego „Constructor Injection”, co oznacza po prostu, że zależność została przekazana jako argument konstruktora. Możesz także użyć setEngine(Engine a)metody „Setter Injection” i tak dalej, ale te podtypy wydają mi się pedantyczne.

Nieco dalej jednak wiele struktur DI zapewnia płytę kotłową do łączenia ze sobą szeregu tych bardziej abstrakcyjnie odwoływanych rzeczy.

Otóż ​​to.


0

Nie jestem ekspertem, ponieważ zacząłem używać DI w ciągu ostatnich kilku lat, ale kilka użytecznych tematów / funkcji pojemników DI, które zauważyłem, to (których nie uważam za produkty składu / polimorfizmu) (ale mogę z tym poradzić):

  • centralne centrum tworzenia obiektów
  • zapewniają singletony według wątków
  • techniki zorientowane na aspekty, takie jak przechwytywanie

0

Oprócz DI istnieje konfiguracja składu klas w aplikacji root (zamiast konfigurowania za pomocą xml). Nie ma potrzeby korzystania z żadnych ram DI lub IoC, nawet jeśli mogą one uporządkować konfigurację składu klas, szczególnie w przypadku dużych projektów. Wynika to z faktu, że środowisko DI zwykle jest dostarczane z kontenerem, który implementuje dodatkowe funkcje, takie jak automatyczne okablowanie, które pomagają konfigurować skład klasy. Możesz przeczytać mój wpis na blogu, aby wyciągnąć moje zrozumienie na ten temat.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.