2016-07-13 13 views
0

Was ist falsch daran, das Abhängigkeitsobjekt als statisches Feld in einer statischen Klasse zu haben, anstatt es in jedes Objekt zu injizieren, das durch Konstruktor davon abhängt?Dependency Injection - Verwenden eines statischen Abhängigkeitsfeldes anstelle des Injizierens in jedes Objekt

public static class Dependencies 
{ 
    public static IUsersRepository Users; 
    ... 
} 
//Use in a method that depends on Users Repository 
var users = Dependencies.Users.GetUsers();  

VS.

public class UserController 
{ 
    private IUsersRepository _users; 
    public UserController(IUsersRepository repo) 
    { 
     this._users = repo; 
    } 
    public List<User> GetCustomUsers() 
    { 
     var users = this._users.GetUsers(); 
     ... 
    } 
} 
+0

Während des Testvorgangs, ich ordne Benutzer Feld zu einem gefälschten Repository – Pharaz

Antwort

0

Um ehrlich zu sein, wird die Polizei nicht an Ihre Tür klopfen, wenn Sie das tun, aber wenn sie zu ihrer logischen Schlussfolgerung kommt (dh eine Anwendung von nennenswerter Größe), landen Sie mit schwierigeren "Spaghetti" Code "Codebasis.

Meistens Kupplung und Dinge wie die SOLID principles. Sie koppeln eng mit der Klasse Dependency zusammen, wenn idealerweise DI dies verhindert, indem Sie Objektgraphen für Sie erstellen und die Abhängigkeiten einspeichern, sodass diese Objekte keine Kenntnis (d. H. Nicht gekoppelt) mit der Implementierung haben, die sie bereitstellt. Wenn Sie einen DI-Container und einen Singleton-Lifestyle verwenden, dann haben Sie im Wesentlichen das, was Sie beschreiben - statische Felder. Aber mit einem Container (auch die "Containerless" Stil Container, die immer beliebter werden) erhalten Sie mehr Flexibilität und die harten Dinge sind für Sie erledigt.

Es gibt einige Fälle, in denen die Verwendung von DI, insbesondere über einen Container, wahrscheinlich eine schlechte Idee ist (Protokollierung, Generierung neuer Guid-Werte, Ermittlung des aktuellen Datums). Sie können diese wenigen Fälle mit der "Umgebungskontext" -Lösung lösen (siehe Matthew Watson's answer für weitere Details).

2

Angenommen, ein UserController eine sofortige IUsersRepository verwenden möchten und eine andere UserController möchte eine Instanz einer anderen IUserRepository Implementierung verwenden, dann können Sie dies nicht mit statischen Abhängigkeiten.

+0

Unter der Annahme, dass alle UserController s nur eine Signle-Instanz von IUsersRepository verwenden, gibt es noch Probleme mit statischen Abhängigkeit Ansatz? – Pharaz

+0

Nein, und Sie brechen nicht die Abhängigkeitsinjektion mit dem Injizieren durch Felder/Eigenschaften.Es ist jedoch immer noch besser, ein Objekt mit festen Abhängigkeiten zu konstruieren, als zu erwarten, dass sich die Objektabhängigkeiten jederzeit während ihrer Lebensdauer ändern können. –

3

Es gibt ein DI-Muster namens "Ambient Context", das Sie dazu verwenden können.

Sie können damit vermeiden, die ganze Zeit übergreifende Bedenken zu äußern, aber es ermöglicht Ihnen immer noch, Unit-Test-Dinge.

Das bekannteste Beispiel ist ein Datetime-Anbieter:

public abstract class TimeProvider { 
    private static TimeProvider current = 
    DefaultTimeProvider.Instance; 

    public static TimeProvider Current { 
     get { return TimeProvider.current; } 
     set { 
     if (value == null) { 
      throw new ArgumentNullException("value"); 
     } 
     TimeProvider.current = value; 
     } 
    } 

    public abstract DateTime UtcNow { get; } 

    public static void ResetToDefault() { 
     TimeProvider.current = DefaultTimeProvider.Instance; 
    } 
} 

Wo eine Implementierung könnte wie folgt aussehen:

public class DefaultTimeProvider : TimeProvider { 
    private readonly static DefaultTimeProvider instance = 
     new DefaultTimeProvider(); 

    private DefaultTimeProvider() { } 

    public override DateTime UtcNow { 
     get { return DateTime.UtcNow; } 
    } 

    public static DefaultTimeProvider Instance { 
     get { return DefaultTimeProvider.instance; } 
    } 
}  

-Code TimeProvider.Current verwenden würde als die Datetime eher für den Zugriff auf DateTime direkt verwenden.

Die standardmäßige konkrete Implementierung gibt das übliche DateTime.UtcNow zurück. Für den Komponententest können Sie jedoch eine spezielle Testimplementierung verwenden und TimeProvider.Current darauf setzen, bevor Sie die Komponententests ausführen.

See this page (where that code comes from) for more information.

Beachten Sie, dass Sie nur dieses Muster für eine wirklich übergreifende Anliegen wie Datum- und Sicherheit, Protokollierung und so weiter verwendet werden soll.

+0

+1 für das Ambient Context-Muster, es ist jedoch eine besondere Lösung für das Problem. Ich habe nach Problemen mit dem statischen Abhängigkeitsansatz gefragt. – Pharaz