Ist die Abhängigkeitsinjektion von Hand eine bessere Alternative zu Zusammensetzung und Polymorphismus?


13

Erstens bin ich ein Programmierer der Einstiegsklasse. Tatsächlich beende ich im Sommer ein AS-Studium mit einem Abschlussprojekt. Wenn ich in meinem neuen Job kein Projekt für mich habe (sie warten darauf, das Team mit weiteren Neueinstellungen zu füllen), habe ich Bücher zum Lesen und Lernen erhalten, während ich warte - einige Lehrbücher, andere nicht so sehr (wie Code Complete). Nachdem ich diese Bücher durchgesehen hatte, wandte ich mich dem Internet zu, um so viel wie möglich zu lernen, und fing an, etwas über SOLID und DI zu lernen (wir sprachen über das Substitutionsprinzip von Liskov, aber nicht über viele andere SOLID-Ideen). Wie ich gelernt habe, habe ich mich hingesetzt, um besser zu lernen, und angefangen, Code zu schreiben, um DI von Hand zu verwenden (es gibt keine DI-Frameworks auf den Entwicklungscomputern).

Während ich es tue, bemerke ich, dass es sich vertraut anfühlt ... und es scheint sehr ähnlich zu sein, wie ich es in der Vergangenheit mit der Komposition abstrakter Klassen unter Verwendung von Polymorphismus getan habe. Vermisse ich hier ein größeres Bild? Gibt es etwas an DI (zumindest von Hand), das darüber hinausgeht? Ich verstehe die Möglichkeit, dass Konfigurationen, die nicht im Code einiger DI-Frameworks enthalten sind, einige große Vorteile haben, wenn es darum geht, Dinge zu ändern, ohne sie neu kompilieren zu müssen, aber wenn ich sie von Hand mache, bin ich mir nicht sicher, ob sie anders sind als oben angegeben ... Ein Einblick in diese wäre sehr hilfreich!

Antworten:


21

Die Grundidee in DI besteht einfach darin, Abhängigkeiten in Objekte zu verschieben, anstatt sie Abhängigkeiten von außen ziehen zu lassen. Dies wurde früher auch als "Umkehrung der Kontrolle" bezeichnet. Dies ermöglicht es, Abhängigkeiten viel besser zu kontrollieren und - nicht zuletzt - Code zu schreiben, der einfach zu testen ist.

DI-Frameworks bauen nur auf dieser Idee auf und automatisieren (teilweise) den oft mühsamen Teil der Verkabelung von Objektabhängigkeiten. Dies kann andernfalls eine erhebliche Menge an Code in einem größeren Projekt erfordern, wenn dies von Hand ausgeführt wird.

Um Abhängigkeiten zu definieren, können heutzutage neben externen Konfigurationsdateien auch Code-Annotationen verwendet werden, z. B. in Sprachen wie Java und C #. Diese können das Beste aus beiden Welten bringen: Verkabelungsabhängigkeiten in einem deklarativen Stil, aber direkt im Code selbst, zu dem er logischerweise gehört. Für mich ist die Möglichkeit, Abhängigkeiten zu ändern, ohne sie neu kompilieren zu müssen, nicht so wertvoll, wie dies im wirklichen Leben selten der Fall ist (abgesehen von einigen Sonderfällen), sondern führt eine oft künstliche Trennung von Abhängigkeiten von den im Code definierten Klassen und Objekten ein .

Um auf Ihre Titelfrage zurückzukommen: DI ist keine Alternative zu Komposition oder Polymorphismus. schließlich ist es möglich gemacht durch diese beiden.


1
Dependency Injection (DI) ist eine Form der Inversion of Control (IoC).
Matthew Flynn

@ MatthewFlynn, in der Tat. Als Referenz: martinfowler.com/articles/injection.html
Péter Török

1
Das ist meine Referenz. Er spricht über die neuen "Lightweight-Container", die die Umkehrung der Steuerung bewirken, was bereits üblich war, da Listener von UI-Ereignissen eine Form von IoC waren. Er bezeichnet die Objektbindung, die Spring und andere IoC-Container ausführen, als Abhängigkeitsinjektion, um sie von der anderen Form der Steuerungsumkehr zu unterscheiden.
Matthew Flynn

Ups - ich habe das "in der Tat" verpasst. Ich dachte du widersprichst mir ... Entschuldigung.
Matthew Flynn

Durch Ihren letzten Absatz fühle ich mich ein bisschen besser. Die ganze Zeit, als ich an meinem kleinen Lernprojekt arbeitete, sagte ich mir immer wieder: "Das fühlt sich wie Polymorphismus an." Leider sind .Net und c # in meinem Job schrecklich veraltet, aber ist Unity das eingebaute c # -Framework, von dem Sie sprechen?
Drake Clarris

22

Der beste Artikel, den ich jemals zu diesem Thema gelesen habe, war der von James Shore . Ich mache seit Ewigkeiten " DI by Hand " als Teil von Abstraktion und Polymorphismus. Nachdem ich in die Berufswelt eingetreten war und immer wieder hörte, dass dieser Begriff herumgeworfen wurde, hatte ich eine große Kluft zwischen dem, was das Wort meiner Meinung nach bedeuten sollte und dem, was es tatsächlich bedeutet:

"Dependency Injection" ist ein 25-Dollar-Begriff für ein 5-Cent-Konzept.

Das ist von Shores Post, der alles für mich geklärt hat. Beispielsweise:

Gegeben

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

Anstatt zu schreiben:

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

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

Du schreibst so etwas:

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

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

...

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

Dies verhindert, dass die CarInstanz bestimmte EngineDetails verarbeiten muss. Ein Auto braucht nur einen Motor, es ist egal, welcher, solange es die grundlegende Motorfunktionalität implementiert. Das heißt, Ihre CarKlasse ist nicht an eine bestimmte Implementierungsabhängigkeit gebunden. Es wird an anderer Stelle "injiziert", möglicherweise zur Laufzeit.

In diesem speziellen Car-Beispiel wird der DI-Untertyp "Constructor Injection" verwendet, was nur bedeutet, dass die Abhängigkeit als Konstruktorargument übergeben wurde. Sie können auch eine setEngine(Engine a)Methode für "Setter Injection" usw. verwenden, aber diese Untertypen erscheinen mir pedantisch.

Ein bisschen weiter bieten viele DI-Frameworks die Boilerplate, um eine Reihe dieser abstrakter referenzierten Dinge miteinander zu verbinden.

Das ist es.


0

Ich bin kein Experte, da ich erst in den letzten Jahren angefangen habe, DI zu verwenden, aber einige der nützlichen Themen / Funktionen von DI-Behältern, die mir aufgefallen sind, sind (die ich nicht als Produkte der Zusammensetzung / des Polymorphismus betrachte (aber ich kann das korrigieren):

  • zentrale Drehscheibe der Objekterstellung
  • Stellen Sie Singletons pro Thread bereit
  • aspektorientierte Techniken wie das Abfangen

0

Abgesehen von DI gibt es in der Stammanwendung eine Konfiguration für die Klassenzusammensetzung (anstatt mit XML zu konfigurieren). Es ist kein DI- oder IoC-Framework erforderlich, obwohl sie die Konfiguration der Klassenzusammensetzung aufräumen können, insbesondere bei großen Projekten. Dies liegt daran, dass das DI-Framework normalerweise mit einem Container geliefert wird, der zusätzliche Funktionen implementiert, z. B. die automatische Verkabelung, mit deren Hilfe die Klassenzusammensetzung konfiguriert werden kann. Sie können meinen Blogeintrag lesen , um mein Verständnis zu diesem Thema zu extrahieren.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.