0

Meine Entity-Klasse hat eine Abhängigkeit von einem Repository.Wie vermeidet man, einen Verweis auf den Container zu übergeben oder CommonServiceLocator für eine EntityFactory zu verwenden

Und ich habe eine EntityFactory-Klasse, die vom Repository zum Erstellen von Entitäten verwendet wird.

public class UserRepository : IUserRepository 
{ 
    private readonly EntityFactory _entityFactory; 

    public UserRepository(EntityFactory entityFactory) 
    { 
     _entityFactory = entityFactory; 
    } 

    ... 
} 

// EntityFactory #1 with no references or dependencies to DI frameworks or CommonServiceLocator 
public class EntityFactory 
{ 
    public User InstantiateUser() 
    { 
     return new User(); // Requires IUserRepository parameter 
    } 
} 

// EntityFactory #2 with reference to Ninject 
using Ninject; 

public class EntityFactory 
{ 
    private readonly IKernel _kernel; 

    public EntityFactory(IKernel kernel) 
    { 
     _kernel = kernel; 
    } 

    public User InstantiateUser(IKernel kernel) 
    { 
     return new User(_kernel.Get<IUserRepository>()); 
    } 
} 

// EntityFactory #3 with reference to CommonServiceLocator 
using Microsoft.Practices.ServiceLocation; 

public class EntityFactory 
{ 
    public User InstantiateUser() 
    { 
     return new User(ServiceLocator.Current.GetInstance<IUserRepository>()); 
    } 
} 

Gibt es eine Möglichkeit, die EntityFactory mit einem Verweis auf den Behälter oder mit dem CommonServiceLocator zu vermeiden? (Context Agnostic)

Oder bin ich gerade dabei, meine Klassen falsch zu gestalten und die User-Klasse sollte nicht von Repositories abhängig sein?

Edit: Hier ist der Code der Methode von David mit:

// Ninject binding 
Bind<Func<User>>().ToMethod(cxt =>() => new User(cxt.Kernel.Get<IUserRepository>())); 

// EntityFactory class 
private readonly Func<User> _userFactory; 
public EntityFactory(Func<User> userFactory) 
{ 
    _userFactory = userFactory; 
} 
public User InstantiateUser() 
{ 
    return userFactory.Invoke(); 
} 
+0

Können Sie nicht einfach 'ServiceLocator.Current.GetInstance ()' oder '_kernel.Get ()' aufrufen? – Steven

Antwort

1

Ihr DI Rahmen sollten Sie mit einem Verfahren zur Erzeugung von Fabriken bieten:

public class EntityFactory 
{ 
    public EntityFactory(Func<User> userFactory) { /* ... */ } 

    public User InstantiateUser() 
    { 
     return userFactory.Invoke(); 
    } 
} 

Wenn die EntityFactory erstellt wird, es wird eine richtige User Fabrik erhalten, die ohne Bezug ordnungsgemäß aufgelöst Benutzer erstellen kann dann dazu verwendet, zum IoC.

+0

Ja, das scheint das zu sein, wonach ich suche. Obwohl ich mir immer noch nicht sicher bin, mehrere Func Factory-Felder in meiner EntityFactory zu haben. Es sieht so aus, als würde man den Code zu sehr modifizieren, um ihn an den DI-Stil anzupassen. Wie würde es mit Unit Testing funktionieren? – Rudy

+0

@Rudy: Wenn Ihre EntityFactory nur Factory-Methoden aufruft, kann es sinnvoll sein, auf sie ganz zu verzichten. Ein anderer wäre, einen kleinen FactoryByTypeCache zu erstellen, der die Factory-Erstellung kapseln/cachen/memoisieren würde. Beim Komponententest können Sie die Factory-Delegaten in Ihrem Container überschreiben und/oder die EntityFactory vollständig ersetzen. (Siehe auch das Repository-Muster) –

0

Was mit Option 2 oder 3 ist falsch? Wenn Sie IoC oder einen Service Locator verwenden, müssen Sie irgendwo einen Verweis darauf haben.

Ich habe einen globalen Verweis auf den IoC-Container und verwenden Sie, um die Schnittstellen überall zu lösen. Dies ähnelt dem Service Locator, verwendet dann aber stattdessen den IoC-Container.

Ich glaube nicht, dass es einen Weg gibt.

+1

Die Optionen 2 oder 3 machen es sehr schwierig, den IoC auszuschalten oder zwei verschiedene Konfigurationen in der gleichen Anwendungsdomäne zu verwenden, da sie statische Referenzen überall verstreuen. Das richtige Verwendungsszenario sollte Verweise auf den IoC nur beim Registrieren von Komponenten und zum Auflösen der "Anwendung" im Orchestrator erfordern. –

+0

Ich glaube, Option 2 implementiert dies tatsächlich und erfordert, dass der IoC-Container übergeben wird, wenn das EntityFractory instanziiert wird. Ich habe IoC implementiert, indem ich einen statischen Klassenwrapper habe, der die Option hat, IoC-Container basierend auf einer "ThreadStatic" -Referenz (dem Kontext der aktuellen Anfrage) zu wechseln. Es ist jedoch auch möglich, einfach eine zweite "Anwendungsdomäne" zu erstellen, wenn der IoC-Container z. ein Modul oder ein Plugin. –

Verwandte Themen