14 Stimmen

Alternativen zur Dependency Injection

Ich bin auf Depency Injektion suchen, kann ich die Vorteile sehen, aber ich habe Probleme mit der Syntax, die es erstellt. Ich habe dieses Beispiel

public class BusinessProducts
{
   IDataContext _dx;

   BusinessProducts(IDataContext dx)
   {
      _dx = dx;
   }

   public List<Product> GetProducts()
   {
    return dx.GetProducts();
   }
}

Das Problem ist, dass ich nicht schreiben will

BusinessProducts bp = new BusinessProducts(dataContextImplementation);

Ich würde weiter schreiben

BusinessProducts bp = new BusinessProducts();

weil ich finde, dass sich die erste Alternative einfach unnatürlich anfühlt. Ich möchte nicht wissen, wovon das BusinessProduct "abhängt", um die Produkte zu erhalten, außerdem habe ich das Gefühl, dass mein Code dadurch unleserlicher wird.

Gibt es irgendwelche Alternativen zu diesem Ansatz, wie ich meine ursprüngliche Syntax für die Erstellung von Objekten behalten möchte, aber ich möchte noch in der Lage sein, die Abhängigkeiten zu fälschen, wenn Unit-Tests oder ist es diese Abhängigkeit Injektion Frameworks für mich tun können?

Ich programmiere in c#, aber Alternativen aus anderen Sprachen sind willkommen

1voto

Strelok Punkte 47933

http://springframework.net/ y http://structuremap.sourceforge.net/Default.htm sind wahrscheinlich die am häufigsten verwendeten DI-Frameworks für .NET-basierte Sprachen und erfüllen beide Ihre Anforderungen.

1voto

Szymon Rozga Punkte 17510

Im Allgemeinen verfügt das Framework selbst über die Logik zum Aufbau des gesamten Objektbaums. Zum Beispiel, anstelle von

new SomeObjectO(diContext)

würden Sie den Rahmen wie folgt aufrufen:

DIFramework.GetNew<SomeObjectO>();

ou

DIFramework.Get<SomeObject>();

Ein weiteres interessantes Framework, das Sie sich ansehen sollten, wenn Sie mehr über DI und den Prozess erfahren möchten, sind die Projekte Unity und Object Builder von Microsoft.

1voto

hangy Punkte 10576

Wenn Sie diese Instanz wirklich nicht in den Konstruktor injizieren möchten, können Sie versuchen, die CommonServiceLocator mit Ihrem bevorzugten kompatiblen .NET Depedency Injection Framework. Dies würde es Ihnen ermöglichen, Code wie diesen zu schreiben:

public class BusinessProducts
{
   IDataContext _dx;

   BusinessProducts()
   {
      _dx = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<IDataContext>();
   }

   public List<Product> GetProducts()
   {
    return dx.GetProducts();
   }
}

Bitte beachten Sie jedoch, dass dies nicht das ist, was die meisten Leute erwarten, wenn sie wissen, dass Sie ein Dependency Injection Framework verwenden. Ich denke, dass es viel üblicher ist, ein Dependency Injection Framework zu verwenden und es alle Objekte für Sie erstellen zu lassen.

BusinessProducts bp = Microsoft.Practices.ServiceLocation.ServiceLocator.Current.GetInstance<BusinessProducts>();

Wenn Sie den Weg über das Dependeny Injection Framework vermeiden möchten, ist die Verwendung einer Factory wahrscheinlich der beste Weg.

1voto

Scott Cowan Punkte 2654

Es gibt eine Technik, die als DI des armen Mannes bezeichnet wird und wie folgt aussieht

public class BusinessProducts
{
   IDataContext _dx;

   BusinessProducts() : this(new DataContext()) {}

   BusinessProducts(IDataContext dx)
   {
      _dx = dx;
   }

   public List<Product> GetProducts()
   {
    return dx.GetProducts();
   }
}

Dies ist nicht ideal, da es Sie an die Implementierung bindet, aber es ist ein gutes Sprungbrett in Richtung entkoppelten Code. dies ist ähnlich wie @tvanfosson, aber viel einfacher.

Ich unterstütze die Empfehlung für Windsor

1voto

Chris Marisic Punkte 31583

Mein Code wird sich auf Microsoft Unity beziehen, aber ich bin mir sicher, dass er auf alle DI-Frameworks anwendbar ist. Wenn Sie DI richtig einsetzen, brauchen Sie nie new BusinessObject(new dataContext) aufzurufen, da die DI-Assoziation alles für Sie erledigt.

Mein Beispiel wird ein wenig lang sein, da ich einige Codes einfügen werde, die ich zum Ausführen einer Model View Presenter-Website verwende, die vollständig von Unity geladen wird. (Wenn Sie den vollständigen Quellcode wollen, besuchen Sie meinen Blog und laden Sie ihn von meinem Assembla SVN-Server herunter)

Laden des Containers (kann im Code erfolgen, wie ich es bevorzuge, oder über die Konfiguration)

protected void Application_Start(object sender, EventArgs e)
{
    Application.GetContainer()
        // presenters / controllers are per request                 
        .RegisterType<IEmployeeController, EmployeeController>(new ContextLifetimeManager<IEmployeeController>())

        //Data Providers are Per session                
        .RegisterType<IEmployeeDataProvider, EmployeeDataProvider>(new SessionLifetimeManager<IEmployeeDataProvider>())

        //Session Factory is life time
        .RegisterType<INHibernateSessionManager, NHibernateSessionManager>(new ContainerControlledLifetimeManager());
}

Das benutzerdefinierte HTTP-Modul ruft die Unity BuildUp-Methode für jede Seite während des OnPreRequest-Aufrufs auf.

private static void OnPreRequestHandlerExecute(object sender, EventArgs e)
{
    var handler = HttpContext.Current.Handler;
    HttpContext.Current.Application.GetContainer().BuildUp(handler.GetType(), handler);

    // User Controls are ready to be built up after the page initialization is complete
    var page = HttpContext.Current.Handler as Page;
    if (page != null)
    {
        page.InitComplete += OnPageInitComplete;
    }
}

Seitencontainer-Präsenter mit dem Attribut [Abhängigkeit] verziert

public partial class Employees : Page, IEmployeeView
{
    private EmployeePresenter _presenter;

    [Dependency]
    public EmployeePresenter Presenter
    {
        set
        {
            _presenter = value;
            _presenter.View = this;
        }
    }
}

Presenter mit InjectionConstructor-Methode

public class EmployeePresenter : Presenter<IEmployeeView>
{
    private readonly IEmployeeController _controller;

    [InjectionConstructor]
    }
    public EmployeePresenter(IEmployeeController controller)
    {
        _controller = controller;
}

Controller folgt dem Beispiel

public class EmployeeController : IEmployeeController
{
    private readonly IEmployeeDataProvider _provider;

    [InjectionConstructor]
    public EmployeeController(IEmployeeDataProvider DataProvider)
    {
        _provider = DataProvider;
    }
}

Dasselbe gilt für Anbieter

public class EmployeeController : IEmployeeController
{
    private readonly IEmployeeDataProvider _provider;

    [InjectionConstructor]
    public EmployeeController(IEmployeeDataProvider DataProvider)
    {
        _provider = DataProvider;
    }
}

Und schließlich der Sitzungsmanager, der nur einen regulären Konstruktor enthält.

public class NHibernateSessionManager : INHibernateSessionManager
{   
    private readonly ISessionFactory _sessionFactory;

    public NHibernateSessionManager()
    {            
        _sessionFactory = GetSessionFactory();
    }
}

Wenn also eine Seitenanforderung gestartet wird, wird die BuildUp()-Methode auf der Seite durch das HttpModul aufgerufen. Unity sieht dann die mit dem Attribut Dependency markierte Eigenschaft und überprüft ihren Container, um zu sehen, ob darin ein EmployeePresenter-Objekt existiert.

Da sich kein solches Objekt im Container befindet, wird er versuchen, einen EmployeePresenter zu erstellen. Bei der Inspektion zur Erstellung der Klasse sieht er, dass innerhalb des Presenters ein Konstruktor erforderlich ist, der einen IEmployeeController benötigt, der in ihn injiziert wird. Da der Container tatsächlich einen Manager für den Controller hat, wird er sehen, ob eine Instanz davon im Container existiert, die zu Beginn der Seitenanforderung nicht existiert, also wird er gehen, um den Controller zu instanzieren.

Unity sieht dann, dass der Controller einen IEmployeeDataProvider benötigt, der in ihn injiziert wird, und setzt diesen Prozess fort, bis er schließlich zu dem Punkt gelangt, an dem der Provider den Sitzungsmanager injiziert haben muss. Da der Sitzungsmanager keine Injektion mehr benötigt, erstellt Unity eine Instanz des Sitzungsmanagers, speichert sie im Container für den gegebenen ContainerLifeTimeManager, injiziert sie in den Provider und speichert diese Instanz, und so weiter bis zu dem Punkt, an dem die Erstellung einer EmployeePresenter-Abhängigkeit für die Seite abgeschlossen ist.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X