2

Il s'agit principalement d'une expérience de réflexion. Donc tout ceci est un exemple de code. Mon objectif était d'utiliser le modèle de spécification pour éliminer les blocs géants de code conditionnel dans une usine. Donc, avec cet exemple, j'ai un objet StatusData que je veux obtenir une implémentation de IStatusUpdate qui est appropriée pour cela.Implémentation d'une fabrique qui utilise les spécifications pour déterminer le type d'objet à créer

Je donne les résultats suivants: Série de tests:

[TestMethod] 
    public void Factory_Interface_Should_Return_IStatusUpdate() 
    { 
     var factory = MockRepository.GenerateMock<IUpdateFactory<StatusData>>(); 
     var obj = MockRepository.GenerateStub<IStatusUpdate>(); 

     var data = new StatusData(); 
     factory.Stub(x => x.Get(data)).Return(obj); 

     var item = factory.Get(data); 

     Assert.IsInstanceOfType(item, typeof(IStatusUpdate)); 
    } 

    [TestMethod] 
    public void StatusUpdateFactory_Should_Return_IStatusUpdate() 
    { 
     var factory = new StatusUpdateFactory(); 
     var data = new StatusData(); 

     var item = factory.Get(data); 

     Assert.IsInstanceOfType(item, typeof(IStatusUpdate)); 
    } 

    [TestMethod] 
    public void StatusUpdateFactory_Should_Return_NewStatusUpdate_When_Status_Is_New() 
    { 
     var data = new StatusData(Status.New); 
     var factory = new StatusUpdateFactory(); 

     var item = factory.Get(data); 

     Assert.IsInstanceOfType(item, typeof(NewStatusUpdate)); 
    } 

Ma mise en œuvre de l'usine semble jusqu'à présent comme ceci:

public class StatusUpdateFactory:IUpdateFactory<StatusData> 
    { 
    public IStatusUpdate Get(StatusData item) 
    { 
     IList<ISpecification<StatusData>> specs = GetSpecifications(); 

     foreach (var spec in specs) 
     { 
     if (spec.IsSatisfiedBy(item)) 
      //how do I do this? 
      return new NewStatusUpdate(); 

     } 
     return null; 
    } 

    private IList<ISpecification<StatusData>> GetSpecifications() 
    { 
     var returnList = new List<ISpecification<StatusData>>(); 
     var specTypes = this.GetType().Assembly.GetTypes() 
         .Where(z => z.IsInstanceOfType(typeof(ISpecification<StatusData>))) 
         .ToList(); 


     specTypes.ForEach(x => returnList.Add(Activator.CreateInstance(x) as ISpecification<StatusData>)); 

     return returnList; 

    } 
    } 

Là où je suis en train de tomber vers le bas est une fois que je l'ai découvert une spécification qui est satisfaite par l'objet d'état, comment mapper cette spécification à un type qui implémente IStatusUpdate. Je suis perplexe. Quelqu'un a suggéré à juste titre que j'avais besoin d'un mappage des spécifications aux implémenteurs IStatusUpdate. Cette cartographie semble être une responsabilité de l'usine, le suspendre de la spécification sent comme une violation de SRP. Je pourrais créer une classe Mapper qui a cette responsabilité mais qui ne semble pas très générique et soulève également la question comment mapper le mappeur à la spécification.

Il y a encore un petit saut ici qui me manque.

Répondre

1

Je suppose donc que nous nous concentrons vraiment sur cet ensemble de lignes:

if (spec.IsSatisfiedBy(item)) 
      return new NewStatusUpdate(); 

et je suppose que vous vous demandez comment sous cette forme actuelle, cela peut être fait. Il semble que l'article devrait soutenir comme

interface ISpecSupport<T> 
{ 
    bool ItemSpecsContain(ISpecification<T> spec); 
} 

Ensuite, la méthode spec.IsSatisfiedBy peut prendre dans ce type d'interface et exécuter la méthode. En d'autres termes, je suppose que je dis que l'objet devrait avoir une sorte de description de ce que c'est (en termes de spécifications). Je devine que c'est une liste de quelque sorte mais je ne suis pas sûr. Je suis sûr que vous avez probablement pensé à cela, donc si vous pouvez ajouter quelque chose qui serait utile.

En outre, au lieu de ce qui précède peut-être vous pouvez réorganiser comme ceci:

if (item.Satisfies(spec)) 
    return new NewStatusUpdate(); 

Alors cette façon, vous ne devez pas utiliser le modèle des visiteurs beaucoup décrié (je pense que ce que je décris avant cette). C'est plus direct puisque l'article semble posséder les spécifications et que vous permettez à l'article de décider s'il répond aux spécifications. Si vous ne voulez pas que cette logique soit contenue dans l'objet (ce que je comprendrais) ET que vous utilisiez un sac de propriétés quelconque (ou que vous soyez cool avec la réflexion), vous pouvez creuser dans les détails de l'objet avec un validateur de spécifications indépendant.En fait, un validateur indépendant n'est peut-être pas une mauvaise idée pour commencer. Je ne suis pas si sûr que la capacité de savoir si une spécification correspond à un élément est une responsabilité qui devrait rester avec une spécification individuelle.

+0

Je pense que c'est la responsabilité des usines de faire ce mapping, n'est-ce pas? alors pourquoi pas un Dictionary pour contenir les mappages qui sont renseignés à l'initialisation de l'usine? – NotMyself

+0

Oui, si une spécification correspond à un type d'élément, alors le dictionnaire a du sens. Je supposais qu'un article pourrait avoir plusieurs spécifications. Et vous avez raison d'utiliser l'usine pour injecter. Je pense vraiment que c'est le point d'avoir l'usine. –

2

Si j'ai bien compris, vous voulez, étant donné un objet implémentant ISpecification, que vous vouliez un objet implémentant IStatusUpdate?

Dans votre échantillon aucun de ces types n'est défini, donc je ne sais pas s'il existe une relation entre eux que vous pourriez utiliser.

Mais vous aurez probablement besoin de l'usine pour contenir le code ou d'une méthode ISpecification.GetUpdate() pour créer l'objet.

+0

Vous me suivez bien .. c'est ce que je cherche. Mais ISpecification.GetUpdate() me semble .. Je suis à la recherche d'un moyen SRP pour accomplir cela peut-être un ISpecificationCommandMapper? – NotMyself

+0

Je ne sais pas pourquoi cela devrait sentir, si cela est fortement plugable (beaucoup de gens les écrivant) en gardant les spécifications et les mises à jour ensemble. Cependant, avec un petit ensemble, les garder ensemble peut-être mieux. Un facteur important est la quantité de logique pour la cartographie. Comme toujours, le contexte est important. – Richard

Questions connexes