2010-10-28 14 views
0

Actuellement, dans le code, j'ai utilisé une fabrique d'objets pour me renvoyer un processeur basé sur une chaîne de caractères, qui a jusqu'à présent été dissocié.Objet fabrique qui crée des objets nécessitant des dépendances

using Core; 
using Data; 

public static class TagProcessorFactory 
{ 
public static ITagProcessor GetProcessor(string tag) 
{ 
    switch (tag) 
    { 
     case "gps0": 
     return new GpsTagProcessor(); 
     case "analog_manager": 
     return new AnalogManagerTagProcessor(); 
     case "input_manager": 
     return new InputManagerTagProcessor(); 
     case "j1939": 
     return new J1939TagProcessor(new MemcachedProvider(new[] { "localhost" }, "DigiGateway"), new PgnRepository()); 
     default: 
     return new UnknownTagProcessor(); 
    } 
} 
} 

appelle le code

var processor = TagProcessorFactory.GetProcessor(tag.Name); 

if (!(processor is UnknownTagProcessor)) 
{ 
    var data = processor.Process(unitId, tag.Values); 

    Trace.WriteLine("Tag <{0}> processed. # of IO Items => {1}".FormatWith(tag.Name, data.Count())); 
} 

que vous pouvez voir l'un de mes articles a des dépendances et im essayant d'exécuter du code de test et je veux passer dans des dépôts simulés et les fournisseurs de cache, mais je peux sembler penser d'un moyen de le faire.

Est-ce une mauvaise conception ou quelqu'un a-t-il des idées pour le réparer pour rendre mon usine testable?

Merci

+1

Y a-t-il une raison impérieuse pour laquelle vous avez décidé de ne pas utiliser l'un des nombreux, nombreux et gratuits et excellents conteneurs d'injection de dépendance disponibles pour C#? Chacun d'entre eux pourrait gérer ce modèle d'injection avec élégance. – anthony

+0

je suis. J'utilise autofac, mon problème est que je ne voulais pas passer dans le constructeur/conteneur pour résoudre la dépendance, iv lire pour ne pas passer le conteneur. – Waterboy4800

+0

Je dirais que le passage d'une usine est acceptable car la classe demande une création différée d'un objet. – aqwert

Répondre

3

Puisque vous utilisez Autofac, vous pouvez profiter de la lookup relationship type:

public class Foo 
{ 
    private readonly IIndex<string, ITagProcessor> _tagProcessorIndex; 

    public Foo(IIndex<string, ITagProvider> tagProcessorIndex) 
    { 
     _tagProcessorIndex = tagProcessorIndex; 
    } 

    public void Process(int unitId, Tag tag) 
    { 
     ITagProcessor processor; 

     if(_tagProcessorIndex.TryGetValue(tag.Name, out processor)) 
     { 
      var data = processor.Process(unitId, tag.Values); 

      Trace.WriteLine("Tag <{0}> processed. # of IO Items => {1}".FormatWith(tag.Name, data.Count())); 
     } 
    } 
} 

Voir la TypedNamedAndKeysServices wiki article pour plus d'informations. Pour enregistrer les différents processeurs, vous associer chacun avec sa clé:

builder.RegisterType<GpsTagProcessor>().Keyed<ITagProcessor>("gps0"); 
builder.RegisterType<AnalogManagerTagProcessor>().Keyed<ITagProcessor>("analog_manager"); 
builder.RegisterType<InputManagerTagProcessor>().Keyed<ITagProcessor>("input_manager"); 

builder 
    .Register(c => new J1939TagProcessor(new MemcachedProvider(new[] { "localhost" }, new PgnRepository())) 
    .Keyed<ITagProcessor>("j1939"); 

Avis Nous ne répertorions UnknownTagProcessor. C'était un signal à l'appelant de l'usine qu'aucun processeur n'a été trouvé pour l'étiquette, que nous exprimons en utilisant TryGetValue à la place.

+0

J'aime cette approche. Ne pense que je ne peux pas comprendre comment résoudre le IIndex à partir du constructeur pour passer dans le constructeur de Foo. Aidez-moi? – Waterboy4800

+0

Les types de relations Autofac sont automatiques. Si vous appelez simplement 'c.Resolve >()', le conteneur interprétera cette requête et créera l'implémentation appropriée pour vous.Cela est vrai même lorsque vous utilisez 'builder.RegisterType ()'. Autre exemple, si vous acceptiez 'Func ', le conteneur reconnaitrait le type de relation et générerait une fonction qui résoud' SomeType'. C'est assez chouette. –

+0

plutôt cool. Merci beaucoup! – Waterboy4800

0

Je vous suggère de regarder à travers another SO post. Il résout plusieurs problèmes à la fois, y compris comment remplacer les valeurs de contructor - sans gâchis. Plus précisément, les paramètres du constructeur deviennent simplement des champs statiques d'une classe "Context", qui sont lus par le constructeur de la classe intérieure.