it-swarm.com.de

IOC Container brechen OOP Prinzipien

Was ist der Zweck von IOC Containern? Die kombinierten Gründe dafür können wie folgt vereinfacht werden:

Bei Verwendung der OOP/SOLID-Entwicklungsprinzipien wird die Abhängigkeitsinjektion unübersichtlich. Entweder haben Sie die Einstiegspunkte der obersten Ebene, die Abhängigkeiten für mehrere Ebenen unter sich verwalten und Abhängigkeiten rekursiv durch die Konstruktion übergeben, oder Sie haben etwas doppelten Code in Factory-/Builder-Mustern und -Schnittstellen, die Abhängigkeiten nach Bedarf erstellen.

Es gibt keine OOP/SOLID-Methode, um dies auszuführen [~ # ~] und [~ # ~] haben super hübschen Code .

Wenn diese vorherige Aussage wahr ist, wie machen es dann IOC Container)? Soweit ich weiß, verwenden sie keine unbekannte Technik, die mit manuellem DI nicht möglich ist. Also die einzige Die Erklärung lautet: IOC Container brechen die OOP/SOLID-Prinzipien, indem sie private Accessoren für statische Objekte verwenden.

Brechen IOC Container die folgenden Prinzipien hinter den Kulissen? Dies ist die eigentliche Frage, da ich ein gutes Verständnis habe, aber das Gefühl habe, dass jemand anderes ein besseres Verständnis hat:

  1. Scope Control. Der Umfang ist der Grund für fast jede Entscheidung, die ich für mein Code-Design treffe. Block, lokal, Modul, statisch/global. Der Umfang sollte sehr explizit sein, so viel wie möglich auf Blockebene und so wenig wie möglich bei Static. Sie sollten Deklarationen, Instanziierungen und Lebenszyklusenden sehen. Ich vertraue darauf, dass die Sprache und der GC den Umfang verwalten, solange ich damit ausdrücklich einverstanden bin. Bei meinen Recherchen habe ich festgestellt, dass IOC Container die meisten oder alle Abhängigkeiten als statisch einrichten und sie über eine AOP-Implementierung hinter den Kulissen steuern. Daher ist nichts transparent.
  2. Kapselung. Was ist der Zweck der Einkapselung? Warum sollten wir private Mitglieder so behalten? Aus praktischen Gründen können Implementierer unserer API die Implementierung nicht durch Ändern des Status (der von der Eigentümerklasse verwaltet werden sollte) unterbrechen. Aus Sicherheitsgründen können jedoch keine Injektionen auftreten, die unsere Mitgliedstaaten überholen und die Validierung und Klassenkontrolle umgehen. Alles (Mocking Frameworks oder IOC Frameworks)), das vor der Kompilierungszeit Code einfügt, um externen Mitgliedern den externen Zugriff zu ermöglichen, ist ziemlich umfangreich.
  3. Prinzip der Einzelverantwortung. An der Oberfläche scheinen IOC Container die Dinge sauberer zu machen. Aber stellen Sie sich vor, wie Sie dasselbe ohne die Helfer-Frameworks erreichen würden. Sie hätten Konstruktoren mit etwa einem Dutzend Abhängigkeiten, die übergeben werden bedeutet nicht, dass Sie es mit IOC Containers, es ist eine gute Sache! Vertuschen! Es ist ein Zeichen, Ihren Code neu zu faktorisieren und SRP zu folgen.
  4. offen/geschlossen. Genau wie SRP nicht nur für Klassen gilt (ich wende SRP auf Einzelverantwortungslinien an, geschweige denn auf Methoden). Open/Closed ist nicht nur eine Theorie auf hoher Ebene, um den Code einer Klasse nicht zu ändern. Es ist eine Praxis, die Konfiguration Ihres Programms zu verstehen und die Kontrolle darüber zu haben, was geändert und was erweitert wird. IOC Container können die Funktionsweise Ihrer Klassen insgesamt teilweise ändern, weil:

    • ein. Der Hauptcode bestimmt nicht das Austauschen von Abhängigkeiten, sondern die Framework-Konfiguration.

    • b. Der Bereich kann zu einem Zeitpunkt geändert werden, der nicht von den aufrufenden Mitgliedern gesteuert wird, sondern extern von einem statischen Framework festgelegt wird.

Die Konfiguration der Klasse ist also nicht wirklich geschlossen, sondern ändert sich basierend auf der Konfiguration eines Tools eines Drittanbieters.

Der Grund, warum dies eine Frage ist, ist, dass ich nicht unbedingt ein Meister aller IOC Container) bin. Und obwohl die Idee eines IOC Containers nett ist, erscheinen sie Um nur eine Fassade zu sein, die eine schlechte Implementierung verdeckt. Um jedoch eine externe Bereichskontrolle, den Zugriff auf private Mitglieder und das langsame Laden zu erreichen, müssen viele nicht triviale fragwürdige Dinge vor sich gehen. AOP ist großartig, aber so wie es ist erreicht durch IOC Container ist ebenfalls fraglich.

Ich kann darauf vertrauen, dass C # und .NET GC das tun, was ich erwarte. Ich kann jedoch nicht dasselbe Vertrauen in ein Drittanbieter-Tool setzen, das meinen kompilierten Code ändert, um Problemumgehungen für Dinge durchzuführen, die ich nicht manuell ausführen könnte.

ZB: Entity Framework und andere ORMs erstellen stark typisierte Objekte und ordnen sie Datenbankentitäten zu. Außerdem bieten sie grundlegende Funktionen für die Durchführung von CRUD. Jeder kann sein eigenes ORM erstellen und die OOP/SOLID-Prinzipien weiterhin manuell befolgen. Diese Rahmenbedingungen helfen uns jedoch, sodass wir das Rad nicht jedes Mal neu erfinden müssen. Während IOC Container, so scheint es, uns helfen, absichtlich die OOP/SOLID-Prinzipien zu umgehen und sie zu vertuschen.

51
Suamere

Ich werde Ihre Punkte numerisch durchgehen, aber zuerst sollten Sie sehr vorsichtig sein: Kombinieren Sie nicht, wie ein Verbraucher eine Bibliothek verwendet, mit der Implementierung der Bibliothek. Gute Beispiele hierfür sind Entity Framework (das Sie selbst als gute Bibliothek zitieren) und die MVC von ASP.NET. Beide machen eine Menge unter der Haube, zum Beispiel mit Reflexion, was absolut nicht als gutes Design angesehen werden würde, wenn Sie es über den täglichen Code verbreiten würden.

Diese Bibliotheken sind absolut nicht "transparent", wie sie funktionieren oder was sie hinter den Kulissen tun. Dies ist jedoch kein Nachteil, da sie gute Programmierprinzipien in ihren Verbrauchern unterstützen. Wenn Sie also über eine solche Bibliothek sprechen, denken Sie daran, dass es als Verbraucher einer Bibliothek nicht Ihre Aufgabe ist, sich um deren Implementierung oder Wartung zu kümmern. Sie sollten sich nur darum kümmern, wie es den von Ihnen geschriebenen Code, der die Bibliothek verwendet, unterstützt oder behindert. Kombinieren Sie diese Konzepte nicht!

Also, um es kurz zu machen:

  1. Sofort erreichen wir das, was ich nur als Beispiel für das oben Gesagte annehmen kann. Sie sagen, dass IOC Container die meisten Abhängigkeiten als statisch einrichten. Nun, vielleicht enthalten einige Implementierungsdetails ihrer Funktionsweise statischen Speicher (obwohl sie dazu neigen, eine Instanz eines Objekts wie Ninjects IKernel zu haben) als ihr Kernspeicher bezweifle ich sogar das. Aber das ist nicht dein Anliegen!

    Tatsächlich ist ein IoC-Container genauso explizit im Umfang wie die Abhängigkeitsinjektion eines armen Mannes. (Ich werde weiterhin IoC-Container mit dem DI eines armen Mannes vergleichen, da ein Vergleich mit keinem DI unfair und verwirrend wäre. Und um klar zu sein, verwende ich "DI eines armen Mannes" nicht als Abwertungsmaßnahme.)

    Im DI eines armen Mannes würden Sie eine Abhängigkeit manuell instanziieren und sie dann in die Klasse einfügen, die sie benötigt. An dem Punkt, an dem Sie die Abhängigkeit erstellen, würden Sie auswählen, was damit geschehen soll. Speichern Sie sie in einer Variablen mit lokalem Gültigkeitsbereich, einer Klassenvariablen oder einer statischen Variablen. Speichern Sie sie überhaupt nicht. Sie können dieselbe Instanz an viele Klassen übergeben oder für jede Klasse eine neue erstellen. Wie auch immer. Der Punkt ist, um zu sehen, was passiert, dass Sie zu dem Punkt schauen - wahrscheinlich in der Nähe des Anwendungsstamms -, an dem die Abhängigkeit erstellt wird.

    Was ist nun mit einem IoC-Container? Nun, du machst genau das Gleiche! Anhand der Ninject-Terminologie sehen Sie sich erneut an, wo die Bindung eingerichtet ist, und finden heraus, ob dort etwas wie InTransientScope, InSingletonScope oder was auch immer steht. Wenn überhaupt, ist dies möglicherweise klarer, da Sie genau dort Code haben, der seinen Umfang deklariert, anstatt eine Methode durchsehen zu müssen, um zu verfolgen, was mit einem Objekt passiert (ein Objekt kann auf einen Block beschränkt sein, wird jedoch mehrfach verwendet Block oder nur einmal, zum Beispiel). Vielleicht stößt Sie die Idee ab, eine Funktion im IoC-Container anstelle einer Rohsprachenfunktion verwenden zu müssen, um den Umfang zu bestimmen, aber solange Sie Ihrer IoC-Bibliothek vertrauen - was Sie sollten! - gibt es keinen wirklichen Nachteil .

  2. Ich weiß immer noch nicht wirklich, wovon du hier sprichst. Betrachten IoC-Container private Eigenschaften als Teil ihrer internen Implementierung? Ich weiß nicht, warum sie es tun würden, aber wenn doch, ist es nicht Ihre Sorge, wie eine von Ihnen verwendete Bibliothek implementiert wird.

    Oder zeigen sie vielleicht eine Fähigkeit wie das Injizieren in private Setter? Ehrlich gesagt bin ich dem noch nie begegnet, und ich bin mir nicht sicher, ob dies wirklich ein gemeinsames Merkmal ist. Aber selbst wenn es da ist, ist es ein einfacher Fall eines Werkzeugs, das missbraucht werden kann. Denken Sie daran, dass es auch ohne IoC-Container nur ein paar Zeilen Reflection-Code gibt, um auf eine private Eigenschaft zuzugreifen und diese zu ändern. Es ist etwas, das Sie fast nie tun sollten, aber das bedeutet nicht, dass .NET schlecht ist, um die Fähigkeit verfügbar zu machen. Wenn jemand ein Werkzeug so offensichtlich und wild missbraucht, ist es die Schuld der Person, nicht die des Werkzeugs.

  3. Der letzte Punkt hier ist ähnlich wie bei 2. Die überwiegende Mehrheit der Zeit, IoC-Container verwenden den Konstruktor ! Die Setter-Injektion wird für ganz bestimmte Umstände angeboten, unter denen aus bestimmten Gründen die Konstruktor-Injektion möglich ist. ' nicht verwendet werden. Jeder, der ständig Setter-Injection verwendet, um zu vertuschen, wie viele Abhängigkeiten übergeben werden, verzichtet massiv auf das Tool. Das ist NICHT die Schuld des Werkzeugs, es ist ihre.

    Wenn dies ein wirklich einfacher Fehler wäre, den unschuldig gemacht werden könnte, und einer, den IoC-Container fördern, dann okay, vielleicht hätten Sie einen Punkt. Es wäre, als würde man jedes Mitglied meiner Klasse öffentlich machen und dann andere beschuldigen, wenn sie Dinge modifizieren, die sie nicht sollten, oder? Aber jeder, der Setter-Injection verwendet, um Verstöße gegen SRP zu vertuschen, ignoriert die grundlegenden Konstruktionsprinzipien entweder absichtlich oder ignoriert sie völlig. Es ist unvernünftig, den IoC-Container dafür verantwortlich zu machen.

    Das ist besonders wahr, weil es auch etwas ist, was man mit DI des armen Mannes genauso einfach machen kann:

    var myObject 
       = new MyTerriblyLargeObject { DependencyA = new Thing(), DependencyB = new Widget(), Dependency C = new Repository(), ... };
    

    Diese Sorge scheint also völlig orthogonal zu der Frage zu sein, ob ein IoC-Container verwendet wird oder nicht.

  4. Das Ändern der Zusammenarbeit Ihrer Klassen ist kein Verstoß gegen OCP. Wenn dies der Fall wäre, würde jede Abhängigkeitsinversion eine Verletzung von OCP fördern. Wenn dies der Fall wäre, wären nicht beide im selben Akronym SOLID!

    Darüber hinaus haben weder die Punkte a) noch b) etwas mit OCP zu tun. Ich weiß nicht einmal, wie ich diese in Bezug auf OCP beantworten soll.

    Das einzige, was ich vermuten kann, ist, dass Sie glauben, dass OCP etwas damit zu tun hat, dass das Verhalten zur Laufzeit nicht geändert wird oder dass im Code der Lebenszyklus von Abhängigkeiten gesteuert wird. Es ist nicht. Bei OCP geht es darum, vorhandenen Code nicht ändern zu müssen, wenn Anforderungen hinzugefügt oder geändert werden. Es geht nur um Schreiben Code, nicht darum, wie Code, den Sie bereits geschrieben haben, zusammengeklebt wird (obwohl natürlich lose Kopplung ein wichtiger Teil für das Erreichen von OCP ist).

Und eine letzte Sache, die Sie sagen:

Ich kann jedoch nicht dasselbe Vertrauen in ein Drittanbieter-Tool setzen, das meinen kompilierten Code ändert, um Problemumgehungen für Dinge durchzuführen, die ich nicht manuell ausführen könnte.

Ja, das kannst du. Es gibt absolut keinen Grund für Sie zu der Annahme, dass diese Tools, auf die sich eine Vielzahl von Projekten stützt, fehlerhafter oder anfälliger für unerwartetes Verhalten sind als jede andere Bibliothek von Drittanbietern.

Nachtrag

Ich habe gerade bemerkt, dass Ihre Intro-Absätze auch eine Adressierung benötigen könnten. Sie sagen sardonisch, dass IoC-Container "keine geheime Technik verwenden, von der wir noch nie gehört haben", um unordentlichen, duplikationsanfälligen Code zum Erstellen eines Abhängigkeitsdiagramms zu vermeiden. Und Sie haben völlig Recht. Sie sprechen diese Dinge tatsächlich mit denselben grundlegenden Techniken an, wie wir Programmierer es immer tun.

Lassen Sie mich Ihnen ein hypothetisches Szenario vorstellen. Als Programmierer stellen Sie eine große Anwendung zusammen, und am Einstiegspunkt, an dem Sie Ihr Objektdiagramm erstellen, stellen Sie fest, dass Sie ziemlich unordentlichen Code haben. Es gibt einige Klassen, die immer wieder verwendet werden, und jedes Mal, wenn Sie eine dieser Klassen erstellen, müssen Sie die gesamte Kette von Abhängigkeiten unter ihnen erneut erstellen. Außerdem haben Sie keine ausdrucksstarke Möglichkeit, den Lebenszyklus von Abhängigkeiten zu deklarieren oder zu steuern, außer mit benutzerdefiniertem Code für jede einzelne. Ihr Code ist unstrukturiert und voller Wiederholungen. Dies ist die Unordnung, über die Sie in Ihrem Intro-Absatz sprechen.

Also fangen Sie zuerst an, ein bisschen umzugestalten - wo ein wiederholter Code so strukturiert ist, dass Sie ihn in Hilfsmethoden herausziehen, und so weiter. Aber dann fangen Sie an zu denken - ist dies ein Problem, das ich vielleicht in einem allgemeinen Sinne angehen könnte, das nicht spezifisch für dieses spezielle Projekt ist, das Ihnen aber bei all Ihren zukünftigen Projekten helfen könnte?

Sie setzen sich also, denken darüber nach und entscheiden, dass es eine Klasse geben soll, die Abhängigkeiten auflösen kann. Und Sie skizzieren, welche öffentlichen Methoden es benötigen würde:

void Bind(Type interfaceType, Type concreteType, bool singleton);
T Resolve<T>();

Bind sagt "Wenn Sie ein Konstruktorargument vom Typ interfaceType sehen, übergeben Sie eine Instanz von concreteType". Der zusätzliche Parameter singleton gibt an, ob jedes Mal dieselbe Instanz von concreteType verwendet oder immer eine neue erstellt werden soll.

Resolve versucht einfach, T mit jedem Konstruktor zu erstellen, dessen Argumente alle zuvor gebundenen Typen sind. Es kann sich auch rekursiv aufrufen, um die Abhängigkeiten vollständig aufzulösen. Wenn eine Instanz nicht aufgelöst werden kann, weil nicht alles gebunden wurde, wird eine Ausnahme ausgelöst.

Sie können versuchen, dies selbst zu implementieren, und Sie werden feststellen, dass Sie ein wenig Nachdenken und etwas Caching für die Bindungen benötigen, bei denen singleton wahr ist, aber sicherlich nichts drastisches oder schreckliches. Und wenn Sie fertig sind- voila, haben Sie den Kern Ihres eigenen IoC-Containers! Ist es wirklich so beängstigend? Der einzige wirkliche Unterschied zwischen diesem und Ninject oder StructureMap oder Castle Windsor oder was auch immer Sie bevorzugen, ist, dass diese viel mehr Funktionen haben, um die (vielen!) Anwendungsfälle abzudecken, in denen diese Basisversion nicht ausreichen würde. Aber im Kern haben Sie die Essenz eines IoC-Containers.

35
Ben Aaronson

Nicht IOC Container brechen viele dieser Prinzipien?

In der Theorie? IoC-Container sind nur ein Werkzeug. Sie können Objekte haben, die eine einzige Verantwortung haben, gut getrennte Schnittstellen, deren Verhalten nach dem Schreiben nicht geändert werden kann usw.

In der Praxis? Absolut.

Ich meine, ich habe nicht wenige Programmierer sagen hören, dass sie IoC-Container speziell verwenden, damit Sie eine Konfiguration verwenden können, um das Verhalten des Systems zu ändern - Verstoß gegen das Open/Closed-Prinzip. Früher gab es Witze über das Codieren in XML, weil 90% ihrer Arbeit darin bestand, die Spring-Konfiguration zu korrigieren. Und Sie haben sicherlich Recht, dass das Ausblenden der Abhängigkeiten (was zugegebenermaßen nicht alle IoC-Container tun) eine schnelle und einfache Möglichkeit ist, hoch gekoppelten und sehr fragilen Code zu erstellen.

Betrachten wir es anders. Betrachten wir eine sehr einfache Klasse mit einer einzigen grundlegenden Abhängigkeit. Es hängt von einem Action ab, einem Delegaten oder Funktor, der keine Parameter akzeptiert und void zurückgibt. Was ist die Verantwortung dieser Klasse? Du kannst es nicht sagen. Ich könnte diese Abhängigkeit so klar nennen wie CleanUpAction, was Sie glauben lässt, dass sie das tut, was Sie wollen. Sobald IoC ins Spiel kommt, wird es zu etwas . Jeder kann in die Konfiguration gehen und Ihre Software ändern, um so ziemlich beliebige Dinge zu tun.

"Wie unterscheidet sich das von der Übergabe eines Action an den Konstruktor?" du fragst. Dies ist anders, da Sie nicht ändern können, was nach der Bereitstellung der Software (oder zur Laufzeit!) An den Konstruktor übergeben wird. Dies ist anders, da Ihre Komponententests (oder die Komponententests Ihrer Kunden) die Szenarien abgedeckt haben, in denen der Delegat an den Konstruktor übergeben wird.

"Aber das ist ein falsches Beispiel! Meine Sachen erlauben keine Verhaltensänderung!" du rufst aus. Tut mir leid, dass ich es dir sage, aber es tut es. Es sei denn, die Schnittstelle, die Sie injizieren, besteht nur aus Daten. Und Ihre Schnittstelle besteht nicht nur aus Daten, denn wenn es nur Daten wären, würden Sie ein einfaches Objekt erstellen und diese verwenden. Sobald Sie eine virtuelle Methode in Ihrem Injektionspunkt haben, lautet der Vertrag Ihrer Klasse mit IoC "Ich kann alles ".

"Wie unterscheidet sich das von der Verwendung von Skripten, um Dinge voranzutreiben? Das ist vollkommen in Ordnung." einige von euch fragen. Es ist nicht anders. Aus Sicht des Programmdesigns gibt es keinen Unterschied. Sie rufen aus Ihrem Programm auf, um beliebigen Code auszuführen. Und sicher, das wird schon seit Ewigkeiten in Spielen gemacht. Es wird in Tonnen von Systemadministrationstools durchgeführt. Ist es OOP? Nicht wirklich.

Es gibt keine Entschuldigung für ihre derzeitige Allgegenwart. IoC-Container haben einen festen Zweck - Ihre Abhängigkeiten zusammenzukleben, wenn Sie so viele Kombinationen davon haben, oder sie verschieben sich so schnell, dass es unpraktisch ist, diese Abhängigkeiten explizit zu machen. Es passen jedoch nur sehr wenige Unternehmen zu diesem Szenario.

27
Telastyn

Verstößt die Verwendung eines IoC-Containers notwendigerweise gegen die OOP/SOLID-Prinzipien? Nein.

Können Sie IoC-Container so verwenden, dass sie gegen OOP/SOLID-Prinzipien verstoßen? Ja.

IoC-Container sind nur Frameworks zum Verwalten von Abhängigkeiten in Ihrer Anwendung.

Sie haben angegeben, dass Lazy-Injektionen, Eigenschaftssetzer und einige andere Funktionen, die ich noch nicht verwenden muss, Ihnen ein weniger als optimales Design bieten können. Die Verwendung dieser spezifischen Funktionen ist jedoch auf Einschränkungen in der Technologie zurückzuführen, in der Sie IoC-Container implementieren.

In ASP.NET WebForms müssen Sie beispielsweise die Eigenschaftsinjektion verwenden, da es nicht möglich ist, ein Page zu instanziieren. Dies ist verständlich, da WebForms niemals mit strengen OOP Paradigmen) entwickelt wurde.

Bei ASP.NET MVC hingegen ist es durchaus möglich, einen IoC-Container mit der sehr OOP/SOLID-freundlichen Konstruktorinjektion zu verwenden.

In diesem Szenario (unter Verwendung der Konstruktorinjektion) werden meines Erachtens aus folgenden Gründen SOLID) Prinzipien gefördert:

  • Prinzip der Einzelverantwortung - Wenn viele Klassen kleiner sind, können diese Klassen sehr spezifisch sein und einen Grund für ihre Existenz haben. Die Verwendung eines IoC-Containers erleichtert die Organisation erheblich.

  • Offen/Geschlossen - Hier kann die Verwendung eines IoC-Containers wirklich glänzen. Sie können die Funktionalität einer Klasse erweitern, indem Sie verschiedene Abhängigkeiten einfügen. Mit Abhängigkeiten, die Sie einfügen, können Sie das Verhalten dieser Klasse ändern. Ein gutes Beispiel ist das Ändern der Klasse, die Sie injizieren, indem Sie einen Dekorateur schreiben, um Caching oder Protokollierung hinzuzufügen. Sie können die Implementierung Ihrer Abhängigkeiten vollständig ändern, wenn Sie in einer geeigneten Abstraktionsebene geschrieben sind.

  • Liskov-Substitutionsprinzip - Nicht wirklich relevant

  • Prinzip der Schnittstellentrennung - Sie können einer einzelnen konkreten Zeit mehrere Schnittstellen zuweisen, wenn Sie möchten. Jeder IoC-Behälter, der ein Salzkorn wert ist, kann dies problemlos tun.

  • Abhängigkeitsinversion - Mit IoC-Containern können Sie die Abhängigkeitsinversion einfach durchführen.

Sie definieren eine Reihe von Abhängigkeiten und deklarieren die Beziehungen und Bereiche sowie den Bing-Bang-Boom: Sie haben auf magische Weise ein Addon, das Ihren Code oder Ihre I.L. Irgendwann und bringt die Dinge zum Laufen. Das ist nicht explizit oder transparent.

Es ist sowohl explizit als auch transparent. Sie müssen Ihrem IoC-Container mitteilen, wie Abhängigkeiten verkabelt und die Objektlebensdauer verwaltet werden sollen. Dies kann entweder durch Konvention, durch Konfigurationsdateien oder durch Code erfolgen, der in die Hauptanwendungen Ihres Systems geschrieben wurde.

Ich bin damit einverstanden, dass beim Schreiben oder Lesen von Code mit IOC Containern) etwas uneleganter Code entfernt wird.

Dies ist der ganze Grund für OOP/SOLID, Systeme verwaltbar zu machen. Die Verwendung eines IoC-Containers entspricht diesem Ziel.

Der Autor dieser Klasse sagt: "Wenn wir keinen IOC Container" verwenden würden, hätte der Konstruktor ein Dutzend Parameter !!! Das ist schrecklich! "

Eine Klasse mit 12 Abhängigkeiten ist wahrscheinlich eine SRP-Verletzung, unabhängig davon, in welchem ​​Kontext Sie sie verwenden.

14
Matthew

Brechen IOC Container nicht beide OOP/SOLID-Prinzipien und erlauben es Codierern, zu brechen?

Mit dem Schlüsselwort static in C # können Entwickler viele OOP/SOLID-Prinzipien brechen, aber es ist unter den richtigen Umständen immer noch ein gültiges Tool.

IoC-Container ermöglichen gut strukturierten Code und reduzieren die kognitive Belastung für Entwickler. Ein IoC-Container kann verwendet werden, um die folgenden SOLID Prinzipien viel einfacher zu machen. Es kann natürlich missbraucht werden, aber wenn wir die Verwendung eines Tools ausschließen würden, das missbraucht werden kann, müssten wir die Programmierung ganz aufgeben.

Während dieses Geschwätz einige gültige Punkte über schlecht geschriebenen Code aufwirft, ist es nicht gerade eine Frage und es ist nicht gerade nützlich.

5
Stephen

Ich sehe mehrere Fehler und Missverständnisse in Ihrer Frage. Der erste wichtige Punkt ist, dass Ihnen die Unterscheidung zwischen Eigenschafts-/Feldinjektion, Konstruktorinjektion und Service Locator fehlt. Es gab viele Diskussionen (z. B. Flammenkriege) darüber, wie man Dinge richtig macht. In Ihrer Frage scheinen Sie nur die Eigenschaftsinjektion anzunehmen und die Konstruktorinjektion zu ignorieren.

Zweitens nehmen Sie an, dass IoC-Container das Design Ihres Codes irgendwie beeinflussen. Sie tun es nicht oder sollten zumindest nicht notwendig sein, das Design Ihres Codes zu ändern, wenn Sie IoC verwenden. Ihre Probleme mit Klassen mit vielen Konstruktoren sind der Fall, dass IoC echte Probleme mit Ihrem Code verbirgt (möglicherweise eine Klasse, die SRP-Unterbrechungen aufweist), und versteckte Abhängigkeiten sind einer der Gründe, warum die Verwendung von Eigenschaftsinjektion und Service Locator nicht empfohlen wird.

Ich verstehe nicht, wo das Problem mit dem Open-Closed-Prinzip liegt, deshalb werde ich es nicht kommentieren. Es fehlt Ihnen jedoch ein Teil von SOLID, der einen großen Einfluss darauf hat: das Prinzip der Abhängigkeitsinversion. Wenn Sie DIP folgen, werden Sie feststellen, dass durch das Invertieren einer Abhängigkeit eine Abstraktion eingeführt wird, deren Implementierung beim Erstellen einer Klasseninstanz aufgelöst werden muss. Mit diesem Ansatz erhalten Sie viele Klassen, für die mehrere Schnittstellen realisiert und bei der Erstellung bereitgestellt werden müssen, damit sie ordnungsgemäß funktionieren. Wenn Sie diese Abhängigkeiten dann manuell bereitstellen würden, müssten Sie viel zusätzliche Arbeit leisten. IoC-Container erleichtern diese Arbeit und ermöglichen es Ihnen sogar, sie zu ändern, ohne das Programm neu kompilieren zu müssen. Sie verwechseln wahrscheinlich das Open/Closed-Prinzip mit dem Dependency Inversion-Prinzip in Ihrer Frage.

Die Antwort auf Ihre Frage lautet also nein. IoC-Container brechen nicht OOP Designprinzipien. Ganz im Gegenteil, sie lösen Probleme, die durch die folgenden SOLID -Prinzipien (insbesondere das Prinzip der Abhängigkeitsinversion) verursacht werden.

3
Euphoric