web-dev-qa-db-fra.com

Ne peut pas combiner usine / di

Il suffit de supposer que j'ai une classe foo, qui a deux dépendances: un ISerializer<T> et un IFileAccessHandler.

Maintenant, cette classe a également d'autres dépendances, dépendances fonctionnelles. Je ne veux pas que quelqu'un instanciant de cette classe dans un état invalide, je devrais donc également passer un objet de domaine dans le constructeur.

Mais comment puis-je avoir cela géré par le CIO lorsque je sais aussi quel objet de domaine passer au moment où je crée la classe FOO?

J'ai fait l'objet de domaine une propriété que j'ai définie par une usine. Donc, l'usine constitue un appel de localisation de service pour obtenir une classe "FOO" correctement instanciée avec ses dépendances et le remplit en outre avec l'objet de domaine correct et le renvoie.

Mais est-ce la meilleure façon d'aller? J'aurais préféré avoir la partie objet de domaine de mon constructeur pour le rendre appariteur que vous devez réellement travailler avec "foo".

Des idées? Est-ce que j'ai râté quelque chose?

45
Laila

La solution par défaut à DI lorsque vous ne pouvez pas filer un type de béton au moment de l'inscription consiste à utiliser une sine abstrait

Dans votre cas, je définirais une interface ifoofactory:

public interface IFooFactory
{
    Foo Create(DomainClass dc);
}

Cela vous permettra de définir une implémentation concrète qui connaît vos services d'infrastructure.

public class FooFactory : IFooFactory
{
    private readonly ISerializer serializer;
    private readonly IFileAccessHandler fileHandler;

    public FooFactory(ISerializer serializer, IFileAccessHandler fileHandler)
    {
        if(serializer == null)
        {
            throw new ArgumentNullException("serializer");
        }
        if(fileHandler == null)
        {
            throw new ArgumentNullException("fileHandler");
        }

        this.serializer = serializer;
        this.fileHandler = fileHandler;
    }

    public Foo Create(DomainClass dc)
    {
        return new Foo(this.serializer, this.fileHandler, dc);
    }
}

De cette façon, vous pouvez protéger les invariants de votre classe FOO, vous permettant de rester avec injection de constructeur.

Dans le conteneur DI, vous pouvez enregistrer la mise en œuvre IfoOfoCactory et correspondante. Partout où vous avez une instance de domaineClass et avez besoin d'une instance FOO, vous prendriez alors une dépendance sur la FIOfoCactory et utilisez cela.

71
Mark Seemann

Je me débats aussi avec ce problème. L'exemple de Mark est contraint dans le fait que la FOOFACTORY crée une classe de béton FOO. Et si c'était pour créer un IFOO où la mise en œuvre est déterminée lors de la configuration de démarrage? Cela impliquerait pour chaque mise en œuvre alternative de l'IFOO (FOOA, FOOB, etc.), vous auriez besoin d'une implémentation concrète de l'usine correspondante (FOOAFACTORY, FOOBFACTORY, etc.). Cela me frappe comme redondant.

Si l'usine est définie au même niveau que la mise en œuvre et l'initialisation du conteneur, je ne vois pas la faiblesse de référencer le conteneur par l'usine. Il conserve toujours des références du conteneur de fuir dans le reste de votre application.

Meilleures salutations,

Métro.

0
Metro