Dies ähnelt der optimierten Antwort, aber ich möchte laut denken - vielleicht sehen andere die Dinge auch so.
Classical OO verwendet Konstruktoren, um den öffentlichen "Initialisierungs" -Vertrag für Verbraucher der Klasse zu definieren (Ausblenden ALLER Implementierungsdetails; auch bekannt als Kapselung). Dieser Vertrag kann sicherstellen, dass Sie nach der Instanziierung ein gebrauchsfertiges Objekt haben (dh keine zusätzlichen Initialisierungsschritte, an die sich der Benutzer erinnern muss (äh, vergessen)).
(Konstruktor) DI unterbricht unbestreitbar die Kapselung, indem es Implementierungsdetails über diese öffentliche Konstruktorschnittstelle blutet . Solange wir den öffentlichen Konstruktor weiterhin für die Definition des Initialisierungsvertrags für Benutzer verantwortlich machen, haben wir einen schrecklichen Verstoß gegen die Kapselung verursacht.
Theoretisches Beispiel:
Class Foo verfügt über 4 Methoden und benötigt eine Ganzzahl für die Initialisierung. Der Konstruktor sieht also wie Foo (int size) aus, und Benutzern der Klasse Foo ist sofort klar, dass sie bei der Instanziierung eine Größe angeben müssen, damit Foo funktioniert.
Angenommen , diese spezielle Implementierung von Foo benötigt möglicherweise auch ein IWidget , um ihre Aufgabe zu erfüllen . Durch die Konstruktorinjektion dieser Abhängigkeit würden wir einen Konstruktor wie Foo erstellen (int size, IWidget-Widget).
Was darüber ärgert mich jetzt haben wir einen Konstruktor, ist Blending Initialisierungsdaten mit Abhängigkeiten - ein Eingang von Interesse für den Benutzer der Klasse ( Größe ), die andere eine interne Abhängigkeit besteht darin , dass nur die Benutzer zu verwirren dient und ist eine Implementierung Detail ( Widget ).
Der Größenparameter ist KEINE Abhängigkeit - es ist einfach ein Initialisierungswert pro Instanz. IoC eignet sich hervorragend für externe Abhängigkeiten (wie Widgets), jedoch nicht für die Initialisierung des internen Status.
Schlimmer noch, was ist, wenn das Widget nur für 2 der 4 Methoden dieser Klasse erforderlich ist? Ich kann Instanziierungs-Overhead für Widget verursachen, obwohl es möglicherweise nicht verwendet wird!
Wie kann man dies kompromittieren / in Einklang bringen?
Ein Ansatz besteht darin, ausschließlich auf Schnittstellen umzuschalten, um den Betriebsvertrag zu definieren. und die Verwendung von Konstruktoren durch Benutzer abschaffen. Um konsistent zu sein, müsste auf alle Objekte nur über Schnittstellen zugegriffen und nur über eine Art Resolver (wie einen IOC / DI-Container) instanziiert werden. Nur der Container kann Dinge instanziieren.
Das kümmert sich um die Widget-Abhängigkeit, aber wie initialisieren wir "Größe", ohne auf eine separate Initialisierungsmethode auf der Foo-Oberfläche zurückzugreifen? Mit dieser Lösung haben wir die Möglichkeit verloren, sicherzustellen, dass eine Instanz von Foo zum Zeitpunkt des Abrufs der Instanz vollständig initialisiert ist. Schade, weil mir die Idee und Einfachheit der Konstruktorinjektion sehr gut gefällt .
Wie erreiche ich eine garantierte Initialisierung in dieser DI-Welt, wenn die Initialisierung MEHR als NUR externe Abhängigkeiten ist?