Inversion of Control befasst sich hauptsächlich mit Abhängigkeitsverwaltung und bietet testbaren Code. Wenn von einer klassischen Herangehensweise eine Klasse abhängig ist, besteht die natürliche Tendenz darin, der Klasse, die die Abhängigkeit hat, direkte Kontrolle über die Verwaltung ihrer Abhängigkeiten zu geben. Dies bedeutet normalerweise, dass die Klasse, die die Abhängigkeit hat, ihre Abhängigkeiten innerhalb eines Konstruktors oder bei Bedarf in ihren Methoden "neu" aufbaut.
Inversion von Control ist nur das ... es invertiert, was Abhängigkeiten erzeugt, diesen Prozess externalisiert und sie in die Klasse einfügt, die die Abhängigkeit hat. Normalerweise ist die Entität, die die Abhängigkeiten erzeugt, ein sogenannter IoC-Container, der nicht nur Abhängigkeiten erzeugt und injiziert, sondern auch deren Lebensdauer verwaltet, ihren Lebensstil bestimmt (mehr dazu in einer Sekunde) und auch eine Vielzahl anbietet von anderen Fähigkeiten. (Dies basiert auf Castle MicroKernel/Windsor, das ist mein IoC-Container der Wahl ... es ist solide geschrieben, sehr funktional und erweiterbar. Es gibt andere IoC-Container, die einfacher sind, wenn Sie einfachere Anforderungen haben, wie Ninject, Microsoft Unity und Spring.NET.)
Bedenken Sie, dass Sie eine interne Anwendung haben, die entweder in einem lokalen Kontext oder einem Remote-Kontext verwendet werden kann. Abhängig von einigen erkennbaren Faktoren muss Ihre Anwendung möglicherweise "lokale" Implementierungen Ihrer Dienste laden, und in anderen Fällen muss sie möglicherweise "entfernte" Implementierungen Ihrer Dienste laden. Wenn Sie dem klassischen Ansatz folgen und Ihre Abhängigkeiten direkt in der Klasse erstellen, die diese Abhängigkeiten hat, dann wird diese Klasse gezwungen sein, zwei sehr wichtige Regeln über die Softwareentwicklung zu brechen: Trennung von Bedenken und Einzelverantwortlichkeit. Sie überschreiten die Grenzen der Besorgnis, weil Ihre Klasse sich nun sowohl mit ihrem eigentlichen Zweck beschäftigt, als auch mit der Frage, welche Abhängigkeiten sie erstellen soll und wie. Die Klasse ist jetzt auch für viele Dinge verantwortlich, und nicht nur für eine Sache, und hat viele Gründe, sich zu ändern: ihr intrinsischer Zweck ändert sich, der Erzeugungsprozess für ihre Abhängigkeiten ändert sich, die Art, wie sich entfernte Abhängigkeiten ändern, welche Abhängigkeiten ihre Abhängigkeiten benötigen , etc.
Indem Sie Ihr Abhängigkeitsmanagement umkehren, können Sie Ihre Systemarchitektur verbessern und SoC und SR verwalten (oder möglicherweise erreichen, wenn Sie zuvor aufgrund von Abhängigkeiten nicht in der Lage waren.) Seit einer externen Entität, dem IoC-Container, wird nun gesteuert Wie Ihre Abhängigkeiten erstellt und injiziert werden, können Sie auch zusätzliche Fähigkeiten erhalten. Der Container kann die Lebenszyklen Ihrer Abhängigkeiten verwalten und sie flexibler erstellen und zerstören, um die Effizienz zu verbessern. Sie erhalten auch die Fähigkeit, die Lebensstile Ihrer Objekte zu verwalten. Wenn Sie eine Art von Abhängigkeit haben, die sehr häufig erstellt, verwendet und zurückgegeben wird, aber wenig oder gar keinen Status hat (z. B. Fabriken), können Sie ihnen einen gepoolten Lebensstil geben, der dem Container automatisch mitteilt ein Objektpool für diesen bestimmten Abhängigkeitstyp. Viele Lebensstile existieren, und ein Behälter wie Schloss Windsor gibt Ihnen normalerweise die Fähigkeit, Ihr eigenes zu verursachen.
Die besseren IoC-Container, wie Castle Windsor, bieten auch eine große Erweiterbarkeit. Standardmäßig können Sie in Windsor Instanzen lokaler Typen erstellen. Es ist möglich, Facilities zu erstellen, die Windsors Erstellungsfunktionen erweitern, um Web-Service-Proxies und WCF-Service-Hosts dynamisch zur Laufzeit zu erstellen, sodass sie nicht manuell oder statisch mit Tools wie svcutil erstellt werden müssen .) Viele Möglichkeiten existieren, um IoC-Unterstützung für existierende Frameworks, wie NHibernate, ActiveRecord etc. zu bringen.
Schließlich erzwingt IoC einen Stil der Kodierung, der Einheit-testbaren Code sicherstellt. Einer der Schlüsselfaktoren, um Code-Einheiten testbar zu machen, ist die Externalisierung des Abhängigkeitsmanagements. Ohne die Möglichkeit, alternative (verspottete, stumpfe usw.) Abhängigkeiten bereitzustellen, ist das Testen einer einzelnen "Einheit" von Code in Isolation eine sehr schwierige Aufgabe, so dass Integrationstests der einzige alternative Stil automatisierter Tests sind. Da IoC erfordert, dass Ihre Klassen Abhängigkeiten durch Injection (durch Konstruktor, Eigenschaft oder Methode) akzeptieren, wird jede Klasse normalerweise, wenn nicht immer, auf eine einzige Verantwortung von ordnungsgemäß separierten Interessen und vollständig ansprechbaren Abhängigkeiten reduziert.
IoC = bessere Architektur, größere Kohäsion, bessere Trennung von Belangen, Klassen, die leichter auf eine einzige Verantwortung reduziert werden können, leicht konfigurierbare und austauschbare Abhängigkeiten (oft ohne eine Neukompilierung Ihres Codes), flexible Abhängigkeits-Stile und Leben Zeitmanagement und testbarer Code für Einheiten. IoC ist so etwas wie ein Lebensstil ... eine Philosophie, ein Ansatz, um gemeinsame Probleme zu lösen und kritische Best Practices wie SoC und SR zu treffen.
Sogar (oder besser gesagt, besonders) mit Hunderten von verschiedenen Implementierungen einer einzelnen Schnittstelle hat IoC viel zu bieten. Es kann eine Weile dauern, bis sich der Kopf vollständig darum dreht, aber sobald Sie vollständig verstanden haben, was IoC ist und was es für Sie tun kann, werden Sie niemals etwas anders machen wollen (außer vielleicht Embedded Systementwicklung ...)
Ich erwähnte absichtlich nicht Tests, weil er erwähnte, dass er DI bereits benutzt. Das ist alles, was Sie wirklich brauchen, um zu verspotten und zu testen. DI ist eine Strategie; IoC-Container erleichtern diese Strategie und erleichtern die Implementierung (eine Reduzierung seines "Makkaroni-Codes"). –
Dies sollte wahrscheinlich als Kommentar zu Jeremys Post gemacht worden sein ... –