it-swarm.com.de

Warum brauche ich einen IoC-Container im Gegensatz zu einfachem DI-Code?

Ich verwende Abhängigkeitsinjektion (DI) für eine Weile und injiziere entweder in einen Konstruktor, eine Eigenschaft oder eine Methode. Ich hatte noch nie das Bedürfnis, einen Inversion of Control (IoC) -Container zu verwenden. Je mehr ich jedoch lese, desto mehr Druck verspüre ich von der Community, einen IoC-Container zu verwenden.

Ich habe mit .NET-Containern wie StructureMap , NInject , nity und Funq gespielt. Ich sehe immer noch nicht, wie ein IoC-Container meinen Code verbessern wird.

Ich habe auch Angst, bei der Arbeit einen Container zu verwenden, weil viele meiner Mitarbeiter Code sehen, den sie nicht verstehen. Viele von ihnen sind möglicherweise nicht bereit, neue Technologien zu erlernen.

Bitte überzeugen Sie mich, dass ich einen IoC-Container verwenden muss. Ich werde diese Argumente verwenden, wenn ich mit meinen Kollegen bei der Arbeit spreche.

598
Vadim

Wow, ich kann nicht glauben, dass Joel dies favorisieren würde:

var svc = new ShippingService(new ProductLocator(), 
   new PricingService(), new InventoryService(), 
   new TrackingRepository(new ConfigProvider()), 
   new Logger(new EmailLogger(new ConfigProvider())));

darüber:

var svc = IoC.Resolve<IShippingService>();

Viele Leute wissen nicht, dass Ihre Abhängigkeitskette verschachtelt werden kann, und es wird schnell unhandlich, sie manuell zu verkabeln. Auch bei Fabriken lohnt sich die Vervielfältigung Ihres Codes nicht.

IoC-Container können komplex sein, ja. Aber für diesen einfachen Fall habe ich gezeigt, dass es unglaublich einfach ist.


Okay, lassen Sie uns das noch mehr rechtfertigen. Angenommen, Sie haben einige Entitäten oder Modellobjekte, die Sie an eine intelligente Benutzeroberfläche binden möchten. Mit dieser intelligenten Benutzeroberfläche (wir nennen sie Shindows Morms) möchten Sie INotifyPropertyChanged implementieren, damit das Tracking der Benutzeroberfläche geändert und die Benutzeroberfläche entsprechend aktualisiert werden kann.

"OK, das hört sich nicht so schwer an", also fangen Sie an zu schreiben.

Sie beginnen damit:

public class Customer
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime CustomerSince { get; set; }
    public string Status { get; set; }
}

..und am Ende mit this:

public class UglyCustomer : INotifyPropertyChanged
{
    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            string oldValue = _firstName;
            _firstName = value;
            if(oldValue != value)
                OnPropertyChanged("FirstName");
        }
    }

    private string _lastName;
    public string LastName
    {
        get { return _lastName; }
        set
        {
            string oldValue = _lastName;
            _lastName = value;
            if(oldValue != value)
                OnPropertyChanged("LastName");
        }
    }

    private DateTime _customerSince;
    public DateTime CustomerSince
    {
        get { return _customerSince; }
        set
        {
            DateTime oldValue = _customerSince;
            _customerSince = value;
            if(oldValue != value)
                OnPropertyChanged("CustomerSince");
        }
    }

    private string _status;
    public string Status
    {
        get { return _status; }
        set
        {
            string oldValue = _status;
            _status = value;
            if(oldValue != value)
                OnPropertyChanged("Status");
        }
    }

    protected virtual void OnPropertyChanged(string property)
    {
        var propertyChanged = PropertyChanged;

        if(propertyChanged != null)
            propertyChanged(this, new PropertyChangedEventArgs(property));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

Das ist ekelhafter Klempner-Code, und ich behaupte, wenn Sie Code wie diesen von Hand schreiben Sie stehlen von Ihrem Client. Es gibt bessere und intelligentere Arbeitsweisen.

Haben Sie diesen Begriff schon einmal gehört, arbeiten Sie schlauer und nicht härter?

Stellen Sie sich vor, ein kluger Kerl in Ihrem Team kam und sagte: "Hier ist ein einfacher Weg."

Wenn Sie Ihre Immobilien virtuell machen (beruhigen Sie sich, es ist nicht so schlimm), können wir das Verhalten dieser Immobilien automatisch einbinden . (Dies nennt sich AOP, aber mach dir keine Sorgen um den Namen. Konzentriere dich darauf, was es für dich tun wird.)

Abhängig davon, welches IoC-Tool Sie verwenden, können Sie Folgendes tun:

var bindingFriendlyInstance = IoC.Resolve<Customer>(new NotifyPropertyChangedWrapper());

Poof! Die gesamte manuelle INotifyPropertyChanged-BS wird jetzt automatisch für Sie auf jedem virtuellen Eigenschaftssetzer des betreffenden Objekts generiert.

Ist das Magie? YES! Wenn Sie der Tatsache vertrauen können, dass dieser Code seine Aufgabe erfüllt, können Sie alle Eigenschaften, die mumbo-jumbo umschließen, sicher überspringen. Sie haben geschäftliche Probleme zu lösen.

Einige andere interessante Verwendungen eines IoC-Tools zur Durchführung von AOP:

  • Deklarative und verschachtelte Datenbanktransaktionen
  • Deklarative & verschachtelte Arbeitseinheit
  • Protokollierung
  • Vor-/Nachbedingungen (Design by Contract)
441
Ben Scheirman

Ich bin bei dir, Vadim. IoC-Container haben ein einfaches, elegantes und nützliches Konzept und machen es mit einem 200-seitigen Handbuch zu etwas, das Sie zwei Tage lang studieren müssen.

Ich persönlich bin verblüfft darüber, wie die IoC-Community einen schönen eleganten Artikel von Martin Fowler aufgenommen und ihn in einen Haufen komplexer Frameworks verwandelt hat, in der Regel mit Handbüchern mit 200 bis 300 Seiten.

Ich versuche nicht zu urteilen (HAHA!), Aber ich denke, dass Menschen, die IoC-Container verwenden, (A) sehr klug sind und (B) nicht genug Einfühlungsvermögen für Menschen haben, die nicht so klug sind wie sie. Alles macht für sie vollkommen Sinn, so dass sie Schwierigkeiten haben zu verstehen, dass viele gewöhnliche Programmierer die Konzepte verwirrend finden. Es ist der Fluch des Wissens . Die Leute, die IoC-Container verstehen, haben Schwierigkeiten zu glauben, dass es Leute gibt, die das nicht verstehen.

Der wertvollste Vorteil der Verwendung eines IoC-Containers besteht darin, dass Sie einen Konfigurationsschalter an einem Ort haben können, mit dem Sie beispielsweise zwischen Testmodus und Produktionsmodus wechseln können. Angenommen, Sie haben zwei Versionen Ihrer Datenbankzugriffsklassen ... eine Version, die aggressiv protokolliert und viele Überprüfungen durchgeführt hat, die Sie während der Entwicklung verwendet haben, und eine andere Version ohne Protokollierung oder Überprüfung, die für die Produktion unglaublich schnell war. Es ist schön, an einem Ort zwischen ihnen wechseln zu können. Andererseits ist dies ein ziemlich triviales Problem, das auf einfachere Weise ohne die Komplexität von IoC-Containern einfach gehandhabt werden kann.

Ich glaube, wenn Sie IoC-Container verwenden, wird Ihr Code ehrlich gesagt viel schwerer zu lesen. Die Anzahl der Stellen, an denen Sie nachsehen müssen, um herauszufinden, was der Code versucht, steigt um mindestens eine Stelle. Und irgendwo im Himmel schreit ein Engel.

138
Joel Spolsky

Vermutlich zwingt Sie niemand, ein DI-Container-Framework zu verwenden. Sie verwenden DI bereits, um Ihre Klassen zu entkoppeln und die Testbarkeit zu verbessern, sodass Sie viele Vorteile erhalten. Kurz gesagt, Sie bevorzugen Einfachheit, was im Allgemeinen gut ist.

Wenn Ihr System einen Komplexitätsgrad erreicht, bei dem die manuelle DI zu einer lästigen Aufgabe wird (dh die Wartung erhöht), vergleichen Sie dies mit der Team-Lernkurve eines DI-Container-Frameworks.

Wenn Sie mehr Kontrolle über die Verwaltung der Abhängigkeitslebensdauer benötigen (d. H., Wenn Sie das Singleton-Muster implementieren möchten), lesen Sie die DI-Container.

Wenn Sie einen DI-Container verwenden, verwenden Sie nur die Funktionen, die Sie benötigen. Überspringen Sie die XML-Konfigurationsdatei und konfigurieren Sie sie im Code, falls dies ausreicht. Bei der Konstruktor-Injektion bleiben. Die Grundlagen von Unity oder StructureMap lassen sich auf ein paar Seiten zusammenfassen.

Es gibt einen großartigen Blog-Beitrag von Mark Seemann zu diesem Thema: Verwendung eines DI-Containers

37
TrueWill

IoC-Container eignen sich auch zum Laden tief verschachtelter Klassenabhängigkeiten. Beispiel: Sie hatten den folgenden Code mithilfe der Abhängigkeitsinjektion.

public void GetPresenter()
{
    var presenter = new CustomerPresenter(new CustomerService(new CustomerRepository(new DB())));
}

class CustomerPresenter
{
    private readonly ICustomerService service;
    public CustomerPresenter(ICustomerService service)
    {
        this.service = service;
    }
}

class CustomerService
{
    private readonly IRespository<Customer> repository;
    public CustomerService(IRespository<Customer> repository)
    {
        this.repository = repository;
    }
}

class CustomerRepository : IRespository<Customer>
{
    private readonly DB db;
    public CustomerRepository(DB db)
    {
        this.db = db;
    }
}

class DB { }

Wenn Sie alle diese Abhängigkeiten in einen IoC-Container geladen haben, können Sie den CustomerService auflösen, und alle untergeordneten Abhängigkeiten werden automatisch aufgelöst.

Zum Beispiel:

public static IoC
{
   private IUnityContainer _container;
   static IoC()
   {
       InitializeIoC();
   }

   static void InitializeIoC()
   {
      _container = new UnityContainer();
      _container.RegisterType<ICustomerService, CustomerService>();
      _container.RegisterType<IRepository<Customer>, CustomerRepository>();
   }

   static T Resolve<T>()
   {
      return _container.Resolve<T>();
   }
}

public void GetPresenter()
{
   var presenter = IoC.Resolve<CustomerPresenter>();
   // presenter is loaded and all of its nested child dependencies 
   // are automatically injected
   // -
   // Also, note that only the Interfaces need to be registered
   // the concrete types like DB and CustomerPresenter will automatically 
   // resolve.
}
32
bendewey

Meiner Meinung nach ist der größte Vorteil einer IoC die Möglichkeit, die Konfiguration Ihrer Abhängigkeiten zu zentralisieren.

Wenn Sie derzeit die Abhängigkeitsinjektion verwenden, sieht Ihr Code möglicherweise so aus

public class CustomerPresenter
{
  public CustomerPresenter() : this(new CustomerView(), new CustomerService())
  {}

  public CustomerPresenter(ICustomerView view, ICustomerService service)
  {
    // init view/service fields
  }
  // readonly view/service fields
}

Wenn Sie im Gegensatz zu den verwirrenderen Konfigurationsdateien eine statische IoC-Klasse verwendet haben, könnten Sie etwa Folgendes haben:

public class CustomerPresenter
{
  public CustomerPresenter() : this(IoC.Resolve<ICustomerView>(), IoC.Resolve<ICustomerService>())
  {}

  public CustomerPresenter(ICustomerView view, ICustomerService service)
  {
    // init view/service fields
  }
  // readonly view/service fields
}

Dann würde Ihre statische IoC-Klasse so aussehen, ich verwende Unity hier.

public static IoC
{
   private static readonly IUnityContainer _container;
   static IoC()
   {
     InitializeIoC();
   }

   static void InitializeIoC()
   {
      _container = new UnityContainer();
      _container.RegisterType<ICustomerView, CustomerView>();
      _container.RegisterType<ICustomerService, CustomerService>();
      // all other RegisterTypes and RegisterInstances can go here in one file.
      // one place to change dependencies is good.
   }
}
32
bendewey

Ich bin ein Fan von deklarativer Programmierung (schauen Sie sich an, wie viele SQL-Fragen ich beantworte), aber die IoC-Container, die ich mir angesehen habe, scheinen zu geheim zu sein.

... oder vielleicht können die Entwickler von IoC-Containern keine eindeutige Dokumentation schreiben.

... oder beides trifft auf den einen oder anderen Grad zu.

Ich denke nicht, dass das Konzept eines IoC-Containers schlecht ist. Die Implementierung muss jedoch leistungsfähig (dh flexibel) genug sein, um in einer Vielzahl von Anwendungen eingesetzt werden zu können, und dennoch einfach und leicht verständlich sein.

Es ist wahrscheinlich sechs von einem und einem halben Dutzend des anderen. Eine reale Anwendung (kein Spielzeug oder Demo) muss komplex sein und viele Eckfälle und Ausnahmen von den Regeln berücksichtigen. Entweder kapseln Sie diese Komplexität in imperativen Code oder in deklarativen Code. Aber irgendwo muss man es darstellen.

28
Bill Karwin

Bei der Verwendung eines Containers geht es hauptsächlich darum, von einem imperativen/skriptbasierten Initialisierungs- und Konfigurationsstil zu einem deklarativen zu wechseln. Dies kann verschiedene positive Auswirkungen haben:

  • Reduzieren von Hairball Startroutinen des Hauptprogramms.
  • Aktivieren ziemlich umfangreicher Rekonfigurationsfunktionen während der Bereitstellung.
  • Injizierbarer Abhängigkeitsstil ist der Weg des geringsten Widerstands für neue Arbeiten.

Natürlich kann es Schwierigkeiten geben:

  • Code, der ein komplexes Start/Herunterfahren/Lebenszyklus-Management erfordert, kann möglicherweise nicht einfach an einen Container angepasst werden.
  • Wahrscheinlich müssen Sie in persönlichen, prozessbezogenen und teamkulturellen Fragen navigieren - aber deshalb haben Sie gefragt ...
  • Einige der Toolkits werden selbst schnell zu Schwergewichten, was die tiefe Abhängigkeit fördert, mit der viele DI-Container als Gegenreaktion begannen.
27
Jeffrey Hantin

Es klingt für mich wie Sie haben bereits Ihren eigenen IoC-Container erstellt (unter Verwendung der verschiedenen Muster, die von Martin Fowler beschrieben wurden) und wir fragen uns, warum die Implementierung eines anderen besser ist als Ihre.

Sie haben also eine Menge Code, der bereits funktioniert. Und fragen sich, warum Sie es durch die Implementierung einer anderen Person ersetzen möchten.

Profis für die Berücksichtigung eines IoC-Containers eines Drittanbieters

  • Sie bekommen Fehler kostenlos behoben
  • Das Bibliotheksdesign ist möglicherweise besser als deins
  • Personen sind möglicherweise bereits mit der jeweiligen Bibliothek vertraut
  • Die Bibliothek ist möglicherweise schneller als Ihre
  • Möglicherweise wurden einige Funktionen implementiert, für die Sie sich eine Implementierung gewünscht haben, für die Sie jedoch nie Zeit hatten. (Haben Sie einen Service-Locator?)

Nachteile

  • Du bekommst kostenlos Bugs vorgestellt :)
  • Das Bibliotheksdesign ist möglicherweise schlechter als deins
  • Sie müssen eine neue API lernen
  • Zu viele Funktionen, die Sie niemals nutzen werden
  • Es ist normalerweise schwieriger, Code zu debuggen, den Sie nicht geschrieben haben
  • Das Migrieren von einem früheren IoC-Container kann mühsam sein

Wägen Sie also Ihre Vor- und Nachteile ab und treffen Sie eine Entscheidung.

23
Sam Saffron

Ich denke, der größte Teil des Werts einer IoC wird durch die Verwendung von DI erzielt. Da Sie dies bereits tun, ist der Rest des Vorteils inkrementell.

Der Wert, den Sie erhalten, hängt von der Art der Anwendung ab, an der Sie arbeiten:

  • Für Mandanten kann der IoC-Container einen Teil des Infrastrukturcodes zum Laden verschiedener Clientressourcen übernehmen. Wenn Sie eine Komponente benötigen, die mandantenspezifisch ist, verwenden Sie einen benutzerdefinierten Selektor, um die Logik zu handhaben, und sorgen Sie sich nicht um den Code Ihres Mandanten. Sie können dies sicherlich selbst erstellen, aber hier ist ein Beispiel wie ein IoC helfen kann.

  • Mit vielen Erweiterungsmöglichkeiten kann die IoC zum Laden von Komponenten aus der Konfiguration verwendet werden. Dies ist eine übliche Sache zu bauen, aber Werkzeuge werden vom Container bereitgestellt.

  • Wenn Sie AOP für einige Querschnittsthemen verwenden möchten, können Sie mit IoC stellt Hooks bereit Methodenaufrufe abfangen. Dies wird seltener bei Ad-hoc-Projekten durchgeführt, aber die IoC erleichtert dies.

Ich habe bereits Funktionen wie diese geschrieben, aber wenn ich jetzt eine dieser Funktionen benötige, würde ich lieber ein vorgefertigtes und getestetes Tool verwenden, wenn es zu meiner Architektur passt.

Wie von anderen erwähnt, können Sie auch zentral konfigurieren, welche Klassen Sie verwenden möchten. Obwohl dies eine gute Sache sein kann, verursacht es Fehlleitungen und Komplikationen. Die Kernkomponenten für die meisten Anwendungen werden nicht viel ersetzt, so dass der Kompromiss etwas schwieriger zu treffen ist.

Ich verwende einen IoC-Container und schätze die Funktionalität, muss aber zugeben, dass ich den Kompromiss bemerkt habe: Mein Code wird auf Klassenebene klarer und auf Anwendungsebene weniger klar (d. H. Visualisierung des Steuerungsflusses).

17
Steven Lyons

Ich bin ein genesender IOC Süchtiger. Ich finde es heutzutage in den meisten Fällen schwierig, die Verwendung von IOC für DI zu rechtfertigen. IOC -Container opfern die Prüfung der Kompilierungszeit und geben Ihnen angeblich im Gegenzug eine "einfache" Einrichtung, ein komplexes Lebensdauermanagement und die sofortige Ermittlung von Abhängigkeiten zur Laufzeit. Ich finde, der Verlust an Kompilierzeit und die daraus resultierenden magischen/Ausnahmen bei der Laufzeit sind in den allermeisten Fällen nichts wert. In großen Unternehmensanwendungen können sie es sehr schwierig machen, die aktuellen Entwicklungen zu verfolgen.

Ich kaufe das Zentralisierungsargument nicht, weil Sie das statische Setup auch sehr einfach zentralisieren können, indem Sie eine abstrakte Factory für Ihre Anwendung verwenden und die Objekterstellung religiös auf die abstrakte Factory verschieben, d. H. Eine ordnungsgemäße DI durchführen.

Warum nicht statische magiefreie DI wie folgt machen:

interface IServiceA { }
interface IServiceB { }
class ServiceA : IServiceA { }
class ServiceB : IServiceB { }

class StubServiceA : IServiceA { }
class StubServiceB : IServiceB { }

interface IRoot { IMiddle Middle { get; set; } }
interface IMiddle { ILeaf Leaf { get; set; } }
interface ILeaf { }

class Root : IRoot
{
    public IMiddle Middle { get; set; }

    public Root(IMiddle middle)
    {
        Middle = middle;
    }

}

class Middle : IMiddle
{
    public ILeaf Leaf { get; set; }

    public Middle(ILeaf leaf)
    {
        Leaf = leaf;
    }
}

class Leaf : ILeaf
{
    IServiceA ServiceA { get; set; }
    IServiceB ServiceB { get; set; }

    public Leaf(IServiceA serviceA, IServiceB serviceB)
    {
        ServiceA = serviceA;
        ServiceB = serviceB;
    }
}


interface IApplicationFactory
{
    IRoot CreateRoot();
}

abstract class ApplicationAbstractFactory : IApplicationFactory
{
    protected abstract IServiceA ServiceA { get; }
    protected abstract IServiceB ServiceB { get; }

    protected IMiddle CreateMiddle()
    {
        return new Middle(CreateLeaf());
    }

    protected ILeaf CreateLeaf()
    {
        return new Leaf(ServiceA,ServiceB);
    }


    public IRoot CreateRoot()
    {
        return new Root(CreateMiddle());
    }
}

class ProductionApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new ServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new ServiceB(); }
    }
}

class FunctionalTestsApplication : ApplicationAbstractFactory
{
    protected override IServiceA ServiceA
    {
        get { return new StubServiceA(); }
    }

    protected override IServiceB ServiceB
    {
        get { return new StubServiceB(); }
    }
}


namespace ConsoleApplication5
{
    class Program
    {
        static void Main(string[] args)
        {
            var factory = new ProductionApplication();
            var root = factory.CreateRoot();

        }
    }

    //[TestFixture]
    class FunctionalTests
    {
        //[Test]
        public void Test()
        {
            var factory = new FunctionalTestsApplication();
            var root = factory.CreateRoot();
        }
    }
}

Ihre Containerkonfiguration ist Ihre abstrakte Factory-Implementierung, Ihre Registrierungen sind Implementierungen von abstrakten Mitgliedern. Wenn Sie eine neue Singleton-Abhängigkeit benötigen, fügen Sie der abstrakten Factory einfach eine weitere abstrakte Eigenschaft hinzu. Wenn Sie eine vorübergehende Abhängigkeit benötigen, fügen Sie einfach eine andere Methode hinzu und fügen Sie sie als Func <> ein.

Vorteile:

  • Die gesamte Konfiguration der Einrichtung und Objekterstellung erfolgt zentral.
  • Konfiguration ist nur Code
  • Die Überprüfung der Kompilierungszeit vereinfacht die Wartung, da Sie nicht vergessen können, Ihre Registrierungen zu aktualisieren.
  • Keine Magie der Laufzeitreflexion

Ich empfehle Skeptikern, das nächste Green-Field-Projekt zu starten und sich ehrlich zu fragen, an welchem ​​Punkt Sie den Container benötigen. Es ist einfach, einen Container IOC später zu berücksichtigen, da Sie lediglich eine Factory-Implementierung durch ein Container-Konfigurationsmodul IOC ersetzen.

16
Maxm007

IoC-Frameworks eignen sich hervorragend, wenn Sie ...

  • ... Typensicherheit wegwerfen. Viele (alle?) IoC-Frameworks zwingen Sie, den Code auszuführen, wenn Sie sicher sein möchten, dass alles korrekt angeschlossen ist. "Hey! Hoffe, ich habe alles eingerichtet, damit meine Initialisierungen dieser 100 Klassen in der Produktion nicht fehlschlagen und Nullzeiger-Ausnahmen auslösen!"

  • ... verunreinigen Sie Ihren Code mit globalen Elementen (IoC-Frameworks handeln all vom Ändern globaler Zustände).

  • ... schreiben Sie beschissenen Code mit unklaren Abhängigkeiten, die sich nur schwer umgestalten lassen, da Sie nie wissen, worauf es ankommt.

Das Problem mit IoC ist, dass die Leute, die sie verwenden, Code wie diesen geschrieben haben

public class Foo {
    public Bar Apa {get;set;}
    Foo() {
        Apa = new Bar();
    }
}

was offensichtlich fehlerhaft ist, da die Abhängigkeit zwischen Foo und Bar fest verdrahtet ist. Dann wurde ihnen klar, dass es besser wäre, Code wie diesen zu schreiben

public class Foo {
    public IBar Apa {get;set;}
    Foo() {
        Apa = IoC<IBar>();
    }
}

das ist auch fehlerhaft, aber weniger offensichtlich. In Haskell wäre die Art von Foo()IO Foo, aber Sie wollen wirklich nicht den IO- Teil und sollten ein Warnsignal dafür sein, dass etwas mit Ihrem Design nicht stimmt, wenn Sie es haben .

Um es loszuwerden (der IO-Teil), holen Sie sich alle Vorteile von IoC-Frameworks und keinen der Nachteile, die Sie stattdessen mit einer abstrakten Factory haben könnten.

Die richtige Lösung wäre so etwas wie

data Foo = Foo { apa :: Bar }

oder vielleicht

data Foo = forall b. (IBar b) => Foo { apa :: b }

und spritzen (aber ich würde es nicht Spritzen nennen) Bar.

Siehe auch dieses Video mit Erik Meijer (Erfinder von LINQ), in dem er sagt, dass DI für Leute ist, die Mathe nicht kennen (und ich könnte nicht mehr zustimmen): http://www.youtube.com)/watch? v = 8Mttjyf-8P4

Im Gegensatz zu Mr. Spolsky glaube ich nicht, dass Leute, die IoC-Frameworks verwenden, sehr schlau sind - ich glaube einfach, dass sie keine Mathematikkenntnisse haben.

14
finnsson

Der größte Vorteil der Verwendung von IoC-Containern für mich (ich persönlich verwende Ninject) bestand darin, dass das Weitergeben von Einstellungen und anderen Arten von globalen Statusobjekten vermieden wurde.

Ich programmiere nicht für das Web, meins ist eine Konsolenanwendung und an vielen Stellen im Objektbaum muss ich Zugriff auf die vom Benutzer festgelegten Einstellungen oder Metadaten haben, die in einem völlig separaten Zweig des Objektbaums erstellt werden. Mit IoC fordere ich Ninject einfach auf, die Einstellungen als Singleton zu behandeln (da es immer nur eine Instanz von ihnen gibt), die Einstellungen oder das Wörterbuch im Konstruktor anzufordern und vorab ... sie erscheinen auf magische Weise, wenn ich sie brauche!

Ohne Verwendung eines IoC-Containers müsste ich die Einstellungen und/oder Metadaten durch 2, 3, ..., n Objekte weitergeben, bevor es tatsächlich von dem Objekt verwendet wird, das es benötigt.

DI/IoC-Container bieten viele weitere Vorteile, wie andere an dieser Stelle ausführlich beschrieben haben. Die Idee, Objekte zu erstellen und anzufordern, kann irrsinnig sein, aber die Verwendung von DI war für mich und mein Team sehr hilfreich, sodass Sie sie vielleicht hinzufügen können in dein Arsenal!

14
Jeffrey Cameron

Ich habe festgestellt, dass die korrekte Implementierung von Dependency Injection Programmierer dazu zwingt, eine Vielzahl anderer Programmiermethoden anzuwenden, die dazu beitragen, die Testbarkeit, Flexibilität, Wartbarkeit und Skalierbarkeit von Code zu verbessern: Methoden wie das Prinzip der Einzelverantwortung, Trennung von Bedenken und Codierung gegen APIs. Es fühlt sich so an, als ob ich gezwungen bin, modularere Klassen und Methoden in Bite-Größe zu schreiben, was das Lesen des Codes erleichtert, da er in Bite-großen Stücken gelesen werden kann.

Es werden jedoch auch tendenziell relativ große Abhängigkeitsbäume erstellt, die über ein Framework (insbesondere bei Verwendung von Konventionen) viel einfacher verwaltet werden können als von Hand. Heute wollte ich etwas sehr schnell in LINQPad testen und dachte, es wäre zu mühsam, einen Kernel zu erstellen und in meine Module zu laden. Am Ende schrieb ich dies von Hand:

var merger = new SimpleWorkflowInstanceMerger(
    new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
    new WorkflowAnswerRowUtil(
        new WorkflowFieldAnswerEntMapper(),
        new ActivityFormFieldDisplayInfoEntMapper(),
        new FieldEntMapper()),
    new AnswerRowMergeInfoRepository());

Rückblickend wäre es schneller gewesen, das IoC-Framework zu verwenden, da die Module so ziemlich alles konventionell definieren.

Nachdem ich einige Zeit damit verbracht habe, die Antworten und Kommentare zu dieser Frage zu studieren, bin ich überzeugt, dass die Leute, die gegen die Verwendung eines IoC-Containers sind, keine echte Abhängigkeitsinjektion praktizieren. Die Beispiele, die ich gesehen habe, sind von Praktiken, die gewöhnlich mit der Abhängigkeitsinjektion verwechselt werden. Einige Leute beschweren sich über Schwierigkeiten beim "Lesen" des Codes. Bei richtiger Ausführung sollte der größte Teil Ihres Codes identisch sein, wenn Sie DI von Hand verwenden, wie wenn Sie einen IoC-Container verwenden. Der Unterschied sollte vollständig in einigen "Startpunkten" innerhalb der Anwendung liegen.

Mit anderen Worten, wenn Sie keine IoC-Container mögen, werden Sie wahrscheinlich keine Dependency Injection so ausführen, wie es soll.

Ein weiterer Punkt: Die Abhängigkeitsinjektion kann nicht von Hand durchgeführt werden, wenn Sie die Reflexion an einer beliebigen Stelle verwenden. Obwohl ich es hasse, was Reflektion für die Code-Navigation bewirkt, muss man erkennen, dass es bestimmte Bereiche gibt, in denen dies nicht zu vermeiden ist. Beispielsweise versucht ASP.NET MVC, den Controller durch Reflektion bei jeder Anforderung zu instanziieren. Um die Abhängigkeitsinjektion manuell durchzuführen, müssten Sie jeden Controller als "Kontextstamm" definieren:

public class MyController : Controller
{
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
    public MyController()
    {
        _simpleMerger = new SimpleWorkflowInstanceMerger(
            new BitFactoryLog(typeof(SimpleWorkflowInstanceMerger).FullName), 
            new WorkflowAnswerRowUtil(
                new WorkflowFieldAnswerEntMapper(),
                new ActivityFormFieldDisplayInfoEntMapper(),
                new FieldEntMapper()),
            new AnswerRowMergeInfoRepository())
    }
    ...
}

Vergleichen Sie dies nun damit, dass ein DI-Framework dies für Sie erledigt:

public MyController : Controller
{
    private readonly ISimpleWorkflowInstanceMerger _simpleMerger;
    public MyController(ISimpleWorkflowInstanceMerger simpleMerger)
    {
        _simpleMerger = simpleMerger;
    }
    ...
}

Beachten Sie bei Verwendung eines DI-Frameworks Folgendes:

  • Ich kann diese Klasse testen. Indem ich ein Modell ISimpleWorkflowInstanceMerger erstelle, kann ich testen, ob es wie erwartet verwendet wird, ohne dass eine Datenbankverbindung oder etwas anderes erforderlich ist.
  • Ich benutze viel weniger Code und der Code ist viel einfacher zu lesen.
  • Wenn sich eine der Abhängigkeiten meiner Abhängigkeit ändert, muss ich keine Änderungen am Controller vornehmen. Dies ist besonders hilfreich, wenn Sie bedenken, dass mehrere Controller wahrscheinlich dieselben Abhängigkeiten verwenden.
  • Ich verweise nie explizit auf Klassen aus meiner Datenschicht. Meine Webanwendung kann nur einen Verweis auf das Projekt enthalten, das die Schnittstelle ISimpleWorkflowInstanceMerger enthält. Auf diese Weise kann ich die Anwendung in separate Module aufteilen und eine echte mehrschichtige Architektur beibehalten, was wiederum die Flexibilität erhöht.

Eine typische Webanwendung verfügt über einige Controller. Der Aufwand für die manuelle Durchführung von DI in jedem Controller summiert sich mit dem Anwachsen Ihrer Anwendung. Wenn Sie eine Anwendung mit nur einem Kontextstamm haben, die niemals versucht, einen Dienst durch Reflektion zu instanziieren, ist dies kein so großes Problem. Die Verwaltung von Anwendungen, die Dependency Injection verwenden, wird jedoch ab einer bestimmten Größe extrem teuer, es sei denn, Sie verwenden ein Framework zum Verwalten des Abhängigkeitsdiagramms.

10

Wann immer Sie das "neue" Schlüsselwort verwenden, erstellen Sie eine konkrete Klassenabhängigkeit und eine kleine Alarmglocke sollte in Ihrem Kopf losgehen. Es wird schwieriger, dieses Objekt isoliert zu testen. Die Lösung besteht darin, Schnittstellen zu programmieren und die Abhängigkeit so zu injizieren, dass das Objekt mit allem, was diese Schnittstelle implementiert, Unit-getestet werden kann (z. B. Mocks).

Das Problem ist, dass Sie irgendwo Objekte konstruieren müssen. Ein Factory-Muster ist eine Möglichkeit, die Kopplung aus Ihren POXOs zu verschieben (Plain Old "fügen Sie Ihre OO Sprache hier ein" Objekte). Wenn Sie und Ihre Mitarbeiter alle Code wie diesen schreiben, ist ein IoC-Container die nächste "inkrementelle Verbesserung", die Sie an Ihrer Codebasis vornehmen können. Dadurch wird der gesamte böse Factory-Code aus Ihren bereinigten Objekten und der Geschäftslogik entfernt. Sie werden es bekommen und es lieben. Zum Teufel, sprechen Sie mit einer Firma darüber, warum Sie es lieben, und begeistern Sie alle.

Wenn Ihre Mitarbeiter noch keine DI durchführen, sollten Sie sich zuerst darauf konzentrieren. Verbreiten Sie das Wort darüber, wie man sauberen Code schreibt, der leicht zu testen ist. Sauberer DI-Code ist der schwierige Teil, wenn Sie erst einmal da sind. Die Verschiebung der Objektverdrahtungslogik von Factory-Klassen zu einem IoC-Container sollte relativ einfach sein.

9
matt burns

Da alle Abhängigkeiten klar erkennbar sind, wird die Erstellung von Komponenten gefördert, die lose gekoppelt sind und gleichzeitig in der gesamten Anwendung leicht zugänglich und wiederverwendbar sind.

8
bbmud

Sie benötigen keinen IoC-Container .

Wenn Sie sich jedoch konsequent an ein DI-Muster halten, werden Sie feststellen, dass mit einem solchen Muster eine Menge redundanten, langweiligen Codes entfernt werden.

Dies ist ohnehin oft die beste Zeit, um eine Bibliothek/ein Framework zu verwenden - wenn Sie verstehen, was es tut, und wenn Sie es ohne die Bibliothek tun können.

7
kyoryu

Ich bin gerade dabei, einheimischen DI-Code herauszureißen und durch ein IOC zu ersetzen. Ich habe wahrscheinlich weit über 200 Codezeilen entfernt und durch ungefähr 10 ersetzt. Ja, ich musste ein wenig lernen, wie man den Container benutzt (Winsor), aber ich bin ein Ingenieur, der an Internettechnologien im Internet arbeitet 21. Jahrhundert also bin ich daran gewöhnt. Ich habe wahrscheinlich ungefähr 20 Minuten damit verbracht, mir die Anleitungen anzusehen. Das war meine Zeit wert.

6
Matt Wrock

Wenn Sie Ihre Klassen weiterhin entkoppeln und Ihre Abhängigkeiten umkehren, bleiben die Klassen weiterhin klein und das "Abhängigkeitsdiagramm" wird immer größer. (Das ist nicht schlecht.) Die Verwendung der Grundfunktionen eines IoC-Containers macht die Verkabelung all dieser Objekte trivial, aber die manuelle Ausführung kann sehr aufwändig sein. Was ist zum Beispiel, wenn ich eine neue Instanz von "Foo" erstellen möchte, aber eine "Leiste" benötigt. Und eine "Bar" braucht ein "A", "B" und "C". Und jeder von denen braucht 3 andere Dinge usw. usw. (Ja, ich kann mir keine guten falschen Namen ausdenken :)).

Durch die Verwendung eines IoC-Containers zum Erstellen Ihres Objektdiagramms wird die Komplexität um ein Vielfaches reduziert und in eine einmalige Konfiguration verschoben. Ich sage einfach "Erschaffe mir ein 'Foo'" und es wird herausgefunden, was benötigt wird, um eines zu bauen.

Einige Leute verwenden die IoC-Container für viel mehr Infrastruktur, was für fortgeschrittene Szenarien in Ordnung ist, aber in diesen Fällen bin ich damit einverstanden, dass sie Code verschleiern und das Lesen und Debuggen für neue Entwickler erschweren können.

5
Aaron Lerch

Dittos über die Einheit. Wenn Sie zu groß werden, können Sie das Knarren in den Sparren hören.

Es überrascht mich nie, wenn die Leute anfangen herauszufinden, wie sauber IoC-Code aussieht, wie die Leute, die einst darüber sprachen, wie Vorlagen in C++ die elegante Art waren, in den 90er Jahren zurück zu gehen, und sie heutzutage als arkane entschlüsseln . Bah!

4
M Lopez

In der .NET-Welt ist AOP nicht allzu beliebt. Für DI ist ein Framework die einzige echte Option, unabhängig davon, ob Sie eines selbst schreiben oder ein anderes Framework verwenden.

Wenn Sie AOP verwendet haben, können Sie diese beim Kompilieren Ihrer Anwendung einfügen, was in Java üblicher ist.

DI bietet viele Vorteile, z. B. eine verringerte Kopplung, sodass das Testen von Einheiten einfacher ist. Wie werden Sie es implementieren? Möchten Sie Reflektion verwenden, um es selbst zu tun?

2
James Black

Es sind also fast drei Jahre vergangen, oder?

  1. 50% derjenigen, die sich für IoC-Frameworks ausgesprochen haben, verstehen den Unterschied zwischen IoC- und IoC-Frameworks nicht. Ich bezweifle, dass sie wissen, dass Sie Code schreiben können, ohne auf einem App-Server bereitgestellt zu werden

  2. Wenn wir das populärste Java Spring-Framework nehmen, wird die IoC-Konfiguration von XMl in den Code verschoben und sieht nun so aus

`@Configuration öffentliche Klasse AppConfig {

public @Bean TransferService transferService() {
    return new TransferServiceImpl(accountRepository());
}

public @Bean AccountRepository accountRepository() {
    return new InMemoryAccountRepository();
}

} `Und dafür brauchen wir ein Framework, warum genau?

2
Ivan

hier ist warum. Das Projekt heißt IOC-with-Ninject. Sie können es mit Visual Studio herunterladen und ausführen. In diesem Beispiel wird Ninject verwendet, aber ALLE "neuen" Anweisungen befinden sich an einer Stelle. Sie können die Ausführung Ihrer Anwendung vollständig ändern, indem Sie das zu verwendende Bindemodul ändern. Das Beispiel ist so eingerichtet, dass Sie sich an eine gespielte Version der Dienste oder an die echte Version binden können. Bei kleinen Projekten spielt das vielleicht keine Rolle, aber bei großen Projekten ist es eine große Sache.

Nur um klar zu sein, Vorteile, wie ich sie sehe: 1) ALLE neue Aussagen in einer Position an der Wurzel des Codes. 2) Code mit einer Änderung komplett neu faktorisieren. 3) Extra Punkte für 'cool factor', weil es ... na ja: cool ist. : p

1
CodeChops

Ehrlich gesagt finde ich nicht, dass es viele Fälle gibt, in denen IoC-Container benötigt werden, und die meiste Zeit fügen sie nur unnötige Komplexität hinzu.

Wenn Sie es nur verwenden, um die Konstruktion eines Objekts zu vereinfachen, müssen Sie sich fragen, ob Sie dieses Objekt an mehr als einer Stelle instanziieren. Würde ein Singleton nicht Ihren Bedürfnissen entsprechen? Ändern Sie die Konfiguration zur Laufzeit? (Wechseln der Datenquellentypen usw.).

Wenn ja, benötigen Sie möglicherweise einen IoC-Container. Wenn nicht, verschieben Sie einfach die Initialisierung von der Stelle, an der der Entwickler sie leicht sehen kann.

Wer hat gesagt, dass eine Schnittstelle besser ist als Vererbung? Angenommen, Sie testen einen Service. Warum nicht Konstruktor DI verwenden und mithilfe der Vererbung Mocks der Abhängigkeiten erstellen? Die meisten Dienste, die ich verwende, haben nur wenige Abhängigkeiten. Wenn Sie auf diese Weise Unit-Tests durchführen, wird die Aufrechterhaltung zahlreicher nutzloser Schnittstellen verhindert, und Sie müssen nicht Resharper verwenden, um die Deklaration einer Methode schnell zu finden.

Ich glaube, dass es für die meisten Implementierungen ein Mythos ist, zu sagen, dass IoC-Container nicht benötigten Code entfernen.

Zuerst wird der Container aufgestellt. Dann müssen Sie noch jedes Objekt definieren, das initialisiert werden muss. Sie speichern Code also nicht bei der Initialisierung, sondern verschieben ihn (es sei denn, Ihr Objekt wird mehrmals verwendet. Ist es besser als Singleton?). Anschließend müssen Sie für jedes Objekt, das Sie auf diese Weise initialisiert haben, eine Schnittstelle erstellen und verwalten.

Hat jemand irgendwelche Gedanken dazu?

1
Fred

Sie würden einen IoC-Container benötigen, wenn Sie die Konfiguration Ihrer Abhängigkeiten zentralisieren müssten, damit sie massenhaft ausgetauscht werden können. Dies ist am sinnvollsten in TDD, wo viele Abhängigkeiten ausgelagert werden, die Abhängigkeiten jedoch kaum voneinander abhängen. Dies geschieht auf Kosten einer gewissen Verschleierung des Steuerungsflusses für die Objektkonstruktion, weshalb eine gut organisierte und hinreichend dokumentierte Konfiguration wichtig ist. Es ist auch gut, einen Grund dafür zu haben, sonst ist es nur Abstraktionsvergoldung . Ich habe gesehen, dass es so schlecht gemacht wurde, dass es zu einer goto-Anweisung für Konstrukteure wurde.

1
DaveMorganTexas

Ich werde versuchen herauszufinden, warum IOC aus meiner Sicht möglicherweise nicht gut ist.

Wie bei allem anderen ist der Container IOC (oder wie Einstein es nennen würde I = OC ^ 2) ein Konzept, bei dem Sie selbst entscheiden müssen, ob Sie ihn in Ihrem Code benötigen oder nicht. Jüngster Modeschrei über IOC ist nur das, Mode. Fallen Sie nicht auf Mode herein, das steht an erster Stelle. Es gibt unzählige Konzepte, die Sie in Ihren Code implementieren können. Erstens verwende ich die Abhängigkeitsinjektion, seit ich mit dem Programmieren begonnen habe, und habe den Begriff selbst gelernt, als er unter diesem Namen populär wurde. Abhängigkeitskontrolle ist ein sehr altes Thema, und es wurde bisher auf Billionen von Wegen angesprochen, je nachdem, was von was entkoppelt wurde. Alles von allem zu entkoppeln ist Unsinn. Das Problem mit dem IOC -Container ist, dass er genauso nützlich sein soll wie Entity Framework oder NHibernate. Während das Schreiben eines objektrelationalen Mappers ein Muss ist, ist der Container IOC nicht immer erforderlich, sobald Sie eine Datenbank mit Ihrem System koppeln müssen. Also, wenn IOC Container nützlich ist:

  1. Wenn Sie eine Situation mit vielen Abhängigkeiten haben, die Sie organisieren möchten
  2. Wenn Sie nicht daran interessiert sind, Ihren Code mit Produkten von Drittanbietern zu koppeln
  3. Wenn Ihre Entwickler lernen möchten, wie sie mit einem neuen Tool arbeiten

1: Es kommt nicht so oft vor, dass Ihr Code so viele Abhängigkeiten aufweist oder dass Sie diese früh im Entwurf kennen. Abstraktes Denken ist nützlich, wenn abstraktes Denken geboten ist.

2: Das Koppeln Ihres Codes mit Code von Drittanbietern ist ein Huge-Problem. Ich habe mit Code gearbeitet, der über 10 Jahre alt ist und der damals ausgefallenen und fortgeschrittenen Konzepten wie ATL, COM, COM + und so weiter folgte. Mit diesem Code können Sie jetzt nichts mehr anfangen. Was ich damit sagen möchte, ist, dass ein fortschrittliches Konzept einen offensichtlichen Vorteil bietet, der jedoch langfristig mit dem veralteten Vorteil selbst aufgehoben wird. Es hatte einfach alles teurer gemacht.

3: Softwareentwicklung ist schwer genug. Sie können es auf nicht erkennbare Ebenen erweitern, wenn Sie ein fortgeschrittenes Konzept in Ihren Code einbauen lassen. Es gibt ein Problem mit IOC2. Obwohl es Abhängigkeiten entkoppelt, entkoppelt es auch den Logikfluss. Stellen Sie sich vor, Sie haben einen Fehler gefunden und müssen eine Pause einlegen, um die Situation zu untersuchen. IOC2 erschwert dies wie jedes andere fortschrittliche Konzept. Das Beheben eines Fehlers innerhalb eines Konzepts ist schwieriger als das Beheben eines Fehlers in einem einfachen Code, da beim Beheben eines Fehlers ein Konzept erneut befolgt werden muss. (Um nur ein Beispiel zu nennen: C++ .NET ändert die Syntax ständig so stark, dass Sie sich Gedanken machen müssen, bevor Sie eine ältere Version von .NET überarbeiten.) Wo liegt also das Problem mit IOC? Das Problem besteht darin, Abhängigkeiten aufzulösen. Die Logik für das Auflösen ist häufig im IOC2 selbst verborgen, möglicherweise in einer ungewöhnlichen Art und Weise, die Sie lernen und pflegen müssen. Wird Ihr Drittanbieterprodukt in 5 Jahren verfügbar sein? Microsoft war es nicht.

"Wir wissen wie" -Syndrom ist überall in Bezug auf IOC2 geschrieben. Dies ähnelt dem Testen der Automatisierung. Ausgefallene Frist und perfekte Lösung auf den ersten Blick, Sie setzen einfach alle Ihre Tests, um über Nacht durchzuführen und die Ergebnisse am Morgen zu sehen. Es ist wirklich schmerzhaft, Unternehmen für Unternehmen zu erklären, was automatisiertes Testen wirklich bedeutet. Automatisierte Tests sind definitiv kein schneller Weg, um die Anzahl der Fehler zu reduzieren, die Sie über Nacht einschleusen können, um die Qualität Ihres Produkts zu verbessern. Aber Mode macht diese Vorstellung ärgerlich dominant. IOC2 leidet unter dem gleichen Syndrom. Es wird angenommen, dass Sie es implementieren müssen, damit Ihre Software gut ist. JEDES Interview wurde ich gefragt, ob ich IOC2 und Automatisierung implementiere. Das ist ein Zeichen der Mode: Das Unternehmen hat einen Teil des Codes in MFC geschrieben, den es nicht aufgeben wird.

Sie müssen IOC2 wie jedes andere Konzept in Software erlernen. Die Entscheidung, ob IOC2 verwendet werden muss, liegt im Team und im Unternehmen. Mindestens ALLE obigen Argumente müssen jedoch erwähnt werden, bevor die Entscheidung getroffen wird. Nur wenn Sie sehen, dass die positive Seite die negative Seite überwiegt, können Sie eine positive Entscheidung treffen.

An IOC2 ist nichts auszusetzen, außer dass es nur die Probleme löst, die es löst, und die Probleme einführt, die es einführt. Nichts anderes. Es ist jedoch sehr schwierig, sich gegen die Mode zu stellen. Sie haben einen schweißtreibenden Mund und Anhänger von allem. Es ist seltsam, wie keiner von ihnen da ist, wenn das Problem mit ihrer Phantasie offensichtlich wird. Viele Konzepte in der Softwareindustrie wurden verteidigt, weil sie Gewinn bringen, Bücher geschrieben, Konferenzen abgehalten und neue Produkte hergestellt werden. Das ist Mode, normalerweise von kurzer Dauer. Sobald Menschen etwas anderes finden, geben sie es vollständig auf. IOC2 ist nützlich, zeigt aber die gleichen Anzeichen wie viele andere verschwundene Konzepte, die ich gesehen habe. Ich weiß nicht, ob es überleben wird. Dafür gibt es keine Regel. Sie denken, wenn es nützlich ist, wird es überleben. Nein, so geht es nicht. Ein großes, reiches Unternehmen ist genug und das Konzept kann innerhalb weniger Wochen aussterben. Wir werden sehen. NHibernate überlebte, EF wurde Zweiter. Vielleicht überlebt IOC2 auch. Vergessen Sie nicht, dass die meisten Konzepte in der Softwareentwicklung nichts Besonderes sind, sie sind sehr logisch, einfach und offensichtlich, und manchmal ist es schwieriger, sich an die aktuelle Namenskonvention zu erinnern, als das Konzept selbst zu verstehen. Macht das Wissen von IOC2 einen Entwickler zu einem besseren Entwickler? Nein, denn wenn ein Entwickler nicht in der Lage wäre, ein Konzept zu entwickeln, das IOC2 ähnelt, ist es für ihn oder sie schwierig zu verstehen, welches Problem IOC2 löst. Wenn es verwendet wird, sieht es künstlich aus und er oder sie beginnt möglicherweise, es zu verwenden um politisch korrekt zu sein.

1
user1228608

Persönlich verwende ich IoC als eine Art Strukturkarte meiner Anwendung (Ja, ich bevorzuge auch StructureMap;)). Es macht es einfach, meine üblichen Schnittstellenimplementierungen während der Tests durch Moq-Implementierungen zu ersetzen. Das Erstellen eines Testaufbaus kann so einfach sein wie ein neuer Init-Aufruf an mein IoC-Framework, wobei jede Klasse, die meine Testgrenze darstellt, durch einen Schein ersetzt wird.

Dies ist wahrscheinlich nicht das, wofür IoC da ist, aber es ist das, wofür ich es am häufigsten benutze.

0
cwap

IOC-BEHÄLTER LÖST EIN PROBLEM, DAS MAN NICHT HABEN KÖNNTE, ABER ES IST EIN SCHÖNES PROBLEM, DAS MAN HABEN MUSS

http://kozmic.net/2012/10/23/ioc-container-solves-a-problem-you-might-not-have-but-its-a-Nice-problem-to-have/

0

Mir ist klar, dass dies ein ziemlich alter Beitrag ist, aber er scheint noch einigermaßen aktiv zu sein, und ich dachte, ich würde ein paar Punkte beisteuern, die in anderen Antworten noch nicht erwähnt wurden.

Ich werde sagen, dass ich mit den Vorteilen der Abhängigkeitsinjektion einverstanden bin, aber ich ziehe es vor, die Objekte selbst zu konstruieren und zu verwalten, wobei ich ein Muster verwende, das dem von Maxm007 in seiner Antwort beschriebenen ähnlich ist. Ich habe zwei Hauptprobleme bei der Verwendung von Containern von Drittanbietern festgestellt:

1) Wenn eine Bibliothek eines Drittanbieters die Lebensdauer Ihrer Objekte "automatisch" verwaltet, kann dies zu unerwarteten Ergebnissen führen. Wir haben festgestellt, dass Sie vor allem in großen Projekten erheblich mehr Kopien eines Objekts haben können, als Sie erwarten, und mehr, als wenn Sie die Lebenszyklen manuell verwalten würden. Ich bin mir sicher, dass dies je nach verwendetem Framework unterschiedlich ist, aber das Problem besteht trotzdem. Dies kann auch problematisch sein, wenn Ihr Objekt Ressourcen, Datenverbindungen usw. enthält, da das Objekt manchmal länger als erwartet leben kann. Daher erhöhen IoC-Container zwangsläufig die Ressourcennutzung und den Speicherbedarf einer Anwendung.

2) IoC-Container sind meiner Meinung nach eine Form der "Black-Box-Programmierung". Ich habe festgestellt, dass insbesondere unsere weniger erfahrenen Entwickler dazu neigen, sie zu missbrauchen. Es ermöglicht dem Programmierer, nicht darüber nachdenken zu müssen, wie sich Objekte zueinander verhalten oder wie sie entkoppelt werden sollen, da es ihnen einen Mechanismus bietet, mit dem sie einfach jedes gewünschte Objekt aus der Luft greifen können. ZB kann es einen guten Designgrund geben, dass ObjectA niemals direkt von ObjectB erfahren sollte, aber anstatt eine Fabrik oder eine Brücke oder einen Service-Locator zu erstellen, sagt ein unerfahrener Programmierer einfach: "Kein Problem, ich nehme einfach ObjectB aus dem IoC-Container ". Dies kann tatsächlich zu einer erhöhten Objektkopplung führen, was durch IoC verhindert werden soll.

0
amnesia

sie benötigen kein Framework, um eine Abhängigkeitsinjektion zu erzielen. Sie können dies auch nach den Java Kernkonzepten tun. http://en.wikipedia.org/wiki/Dependency_injection#Code_illustration_using_Java