1

J'ai du mal à comprendre certaines parties de l'utilisation de StructureMap. En particulier, dans la documentation une déclaration est faite au sujet d'un anti-modèle commun, l'utilisation de StructureMap comme un localisateur de service uniquement au lieu de l'injection de constructeur (échantillons de code directement à partir de la documentation StructureMap):Injection constructeur et quand utiliser un localisateur de service

public ShippingScreenPresenter() 
    { 
     _service = ObjectFactory.GetInstance<IShippingService>(); 
     _repository = ObjectFactory.GetInstance<IRepository>(); 
    } 

au lieu de:

public ShippingScreenPresenter(IShippingService service, IRepository repository) 
    { 
     _service = service; 
     _repository = repository; 
    } 

Ceci est très bien pour un très court objet graphique, mais en présence d'objets de niveaux profonds, cela implique que vous devez transmettre toutes les dépendances requises par les objets plus profonds droit du haut? Cela brise certainement l'encapsulation et expose trop d'informations sur la mise en œuvre d'objets plus profonds. Supposons que j'utilise le modèle Enregistrement actif. Mon enregistrement doit donc pouvoir accéder à un référentiel de données pour pouvoir enregistrer et charger lui-même. Si cet enregistrement est chargé dans un objet, cet objet appelle-t-il ObjectFactory.CreateInstance() et le transmet-il au constructeur de l'enregistrement actif? Que faire si cet objet est à l'intérieur d'un autre objet. Est-ce qu'il prend l'IRepository dans son propre paramètre de plus haut? Cela exposerait à l'objet parent le fait que nous accédions au référentiel de données à ce stade, ce que l'objet externe ne devrait probablement pas savoir.

public class OuterClass 
{ 
    public OuterClass(IRepository repository) 
    { 
     // Why should I know that ThingThatNeedsRecord needs a repository? 
     // that smells like exposed implementation to me, especially since 
     // ThingThatNeedsRecord doesn't use the repo itself, but passes it 
     // to the record. 
     // Also where do I create repository? Have to instantiate it somewhere 
     // up the chain of objects 
     ThingThatNeedsRecord thing = new ThingThatNeedsRecord(repository); 
     thing.GetAnswer("question"); 
    } 
} 

public class ThingThatNeedsRecord 
{ 
    public ThingThatNeedsRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public string GetAnswer(string someParam) 
    { 
     // create activeRecord(s) and process, returning some result 
     // part of which contains: 
     ActiveRecord record = new ActiveRecord(repository, key); 
    } 

    private IRepository repository; 
} 

public class ActiveRecord 
{ 
    public ActiveRecord(IRepository repository) 
    { 
     this.repository = repository; 
    } 

    public ActiveRecord(IRepository repository, int primaryKey); 
    { 
     this.repositry = repository; 
     Load(primaryKey); 
    } 

    public void Save(); 

    private void Load(int primaryKey) 
    { 
     this.primaryKey = primaryKey; 
     // access the database via the repository and set someData 
    } 

    private IRepository repository; 
    private int primaryKey; 
    private string someData; 
} 

Toutes les pensées seraient appréciées.

Simon

EDIT: Avis semble que l'injection doit commencer à la couche supérieure. ActiveRecord serait injecté dans ThingThatNeedsRecord qui est injecté dans OuterClass. Le problème avec ceci serait que si ActiveRecord doit être instancié avec un paramètre d'exécution (l'identifiant de l'enregistrement à récupérer par exemple). Si j'injecte ActiveRecord dans ThingThatNeedsRecord tout en haut, je dois d'une manière ou d'une autre déterminer quel id doit être à ce point (ce qui expose la couche supérieure à l'implémentation qu'elle ne devrait pas) ou je dois avoir un ActiveRecord partiellement construit et définissez l'Id plus tard. Cela devient plus compliqué si j'ai besoin de N enregistrements et je ne le saurai pas avant l'exécution de la logique à l'intérieur de ThingThatNeedsRecord.

+0

Copie possible: http://stackoverflow.com/questions/4570750/dependency-injection-turtles-all-the-way-down –

+0

En relation: http://stackoverflow.com/questions/2420193/dependency-injection- constructeur-folie/2420245 # 2420245 –

Répondre

6

Inversion de contrôle est comme la violence. Si cela ne résout pas votre problème, vous n'en utilisez pas assez. Ou something like that. Plus précisément, je pense que votre OuterClass devrait avoir ThingThatNeedsRecord injecté dedans via l'injection du constructeur. De même ThingThatNeedsRecord devrait avoir ActiveRecord injecté dedans. Non seulement cela résoudra votre problème immédiat, mais cela rendra votre code plus modulaire et testable.

+0

Je pense que cela remonte à mon inquiétude originale. Si je crée ThingThatNeedsRecord au-dessus de OuterClass et y injecte ActiveRecord, l'objet au-dessus de OuterClass est exposé aux implémentations internes de ThingThatNeedsRecord dans le graphe d'objets. – Simon

+0

Si vous créez 'OuterClass' via le conteneur (StructureMap), le code qui utilise' OuterClass' n'est pas exposé à la dépendance de 'ThingThatNeedsRecord'. Correctement configuré, le conteneur fournira 'ThingThatNeedsRecord' à' OuterClass', ainsi que la gestion récursive des autres dépendances dans le graphe d'objets. –

+1

Finalement, au niveau supérieur, vous aurez un appel de localisation de service, où vous obtenez un objet en ObjectFactory. Cependant, toutes les dépendances de cet objet (et leurs dépendances) seront satisfaites par le conteneur, ainsi le code qui effectue l'appel d'emplacement de service n'a pas besoin de connaître ces dépendances. –

Questions connexes