2010-02-19 5 views
3

Je réfléchis actuellement à quel modèle je devrais résoudre le problème suivant.Modèle d'usine ou de service ou injection de méthode?

J'ai une entité appelée IdentificationRequest. Cette entité est utilisée pour identifier un Person selon certains critères.

public class IdentificationRequest 
{ 
    public IdentificationCriteria Criteria; 
    public Person IdentifiedPerson; 

    protected internal virtual void RedirectToManualIdentification() 
    { 
     ChangeState(IdentificationRequestState.ManualIdentificationRequested); 
    } 

    public virtual void StartManualIdentification() 
    { 
     ChangeState(IdentificationRequestState.ManualIdentificationInProgress); 
    } 

    public virtual void AssignIdentifiedPerson(Person person) 
    { 
     identifiedPerson = person; 
     ChangeState(IdentificationRequestState.IdentificationFinished);  
    } 
} 

public class IdentificationCriteria 
{ 
    public string Name; 
} 

Ceci est un exemple simplifié. En realitiy le IdentificationRequest contient beaucoup plus d'informations, ainsi que le IdentificationCriteria.

Donc, fondamentalement, un client crée un IdentificationRequest avec son IdentificationCriteria et le bon Person doit être identifié. Pour cela, les critères doivent être transmis à la couche de persistance pour vérifier si une personne dans la base de données correspond aux critères. Si aucune personne ne peut être trouvée, une interaction humaine est alors requise pour assigner le bon Person à la demande.

Pour le processus d'identification, j'utilise actuellement un service. Comme:

public class IdentificationService : IIdentificationService 
     { 
      private readonly IPersonRepository personRepository ; 
      private readonly IIdentificationRequestRepository identificationRequestRepository; 

      public IdentificationService(IPersonRepository personRepository) 
      { 
       this.personRepository = personRepository ; 
      } 

      public bool IdentifyPerson(IdentificationRequest identificationRequest) 
      { 
       var matches = personRepository.FindByIdentificationCriteria(identificationRequest.Criteria); 

       // some additional post analysis of the matches returned from the persistence layer 
       var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest.Criteria); 
       var uniqueMatch = criteriaAnalyzer.TryIdentify(matches); 

       if(uniqueMatch != null) 
       { 
        identificationRequest.AssignIdentifiedPerson(uniqueMatch); 
        return true; 
       } 
       else 
       { 
        identificationRequest.RedirectToManualIdentification(); 
        return false; 
       }    
      } 
     } 

Ce service fait partie de l'assembly de domaine. Maintenant, ma question est, si c'est le bon modèle pour effectuer l'identification? Ou devrais-je utiliser une usine, pour créer la demande d'identification puis essayez directement de l'identifier, comme:

public class IdentificationRequestFactory 
{ 
    private readonly IPersonRepository personRepository; 

    public IdentificationRequestFactory(IPersonRepository personRepository) 
    { 
     this.personRepository = personRepository; 
    } 

    public IdentificationRequest Create(IdentificationCriteria identificationCriteria) 
    { 
     var request = new IdentificationRequest(identificationCriteria); 

     var matches = personRepository.FindByIdentificationCriteria(identificationRequest.Criteria); 
     var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest.Criteria); 
     var uniqueMatch = criteriaAnalyzer.TryIdentify(matches); 

     if(uniqueMatch != null) 
     { 
      identificationRequest.AssignIdentifiedPerson(uniqueMatch); 

     } 
     else 
     { 
      identificationRequest.RedirectToManualIdentification(); 

     } 

     return request; 
    } 
} 

De cette façon, un IdentificationRequest ne peut être construit par l'usine, en veillant à ce que le processus d'identification est déjà fait et la demande est dans un état valide.

Ou voulez-vous laisser le IdentificationRequest s'identifier en faisant une injection de méthode comme:

public class IdentificationRequest 
{ 
    public IdentificationCriteria Criteria; 
    public Person IdentifiedPerson; 

    public void Identify(IPersonRepository personRepository) 
    { 
     // identification logic here 
    } 
} 

Cet exemple coupler le processus d'identification à la demande directement.

Qu'est-ce qu'un modèle commun pour un tel cas? Y a-t-il un modèle commun de toute façon? Quels sont les avantages et inconvénients?

Merci d'avance!

Mise à jour

Peut-être que je ne comprends pas le motif de commande correctement, mais quels avantages puis-je obtenir de celui-ci dans ce cas? L'implémentation suivante est-elle correcte?

public class IdentificationCommandFactory 
{ 
    private readonly IPersonRepository personRepository; 

    public IdentificationCommandFactory(IPersonRepository personRepository) 
    { 

     this.personRepository = personRepository; 
    } 

    public IIdentificationCommand Create(IdentificationRequest identificationRequest) 
    { 
     var matches = personRepository.FindByIdentificationCriteria(identificationRequest); 
     var criteriaAnalyzer = new IdentificationCriteriaAnalyzer(identificationRequest); 
     var uniqueMatch = criteriaAnalyzer.TryIdentify(matches); 

     if(uniqueMatch != null) 
     {     
      return new AssignIdentifiedPersonCommand(identificationRequest, uniqueMatch); 
     } 
     else 
     {     
      return new RedirectToManualIdentificationCommand(identificationRequest); 
     }  
    } 

} 

public interface IIdentificationCommand 
{ 
    void Execute(); 
} 

public class RedirectToManualIdentificationCommand : IIdentificationCommand 
{ 
    private readonly IdentificationRequest identificationRequest; 

    public RedirectToManualIdentificationCommand(IdentificationRequest identificationRequest) 
    { 
     this.identificationRequest = identificationRequest; 
    } 

    public void Execute() 
    { 
     identificationRequest.RedirectToManualIdentification(); 
    } 
} 

public class AssignIdentifiedPersonCommand : IIdentificationCommand 
{ 
    private readonly IdentificationRequest identificationRequest; 
    private readonly Person personIdentified; 

    public AssignIdentifiedPersonCommand(IdentificationRequest identificationRequest, Person personIdentified) 
    { 
     this.identificationRequest = identificationRequest; 
     this.personIdentified = personIdentified; 
    } 

    public void Execute() 
    { 
     identificationRequest.AssignIdentifiedPerson(personIdentified); 
    } 
} 

L'appelant:

var identificationCommandFactory = new IdentificationCommandFactory(personRepository); 

    var command = identificationCommandFactory.Create(request); 

    command.Execute(); 

Répondre

5

L'objectif principal de votre développement devrait être de répondre aux exigences avec le code le plus simple et le plus propre possible. Cela dit, à moins que vous ayez une raison particulière d'utiliser l'un de ces motifs, arrêtez-vous maintenant. (http://msdn.microsoft.com/en-us/magazine/cc163962.aspx)

S'il n'y a pas de raison spécifique d'aller à ce travail, vous écrivez simplement plus de code dans l'espoir qu'il vous sera utile un jour. Il suffit d'écrire ce qui fonctionne. Refactoriser plus tard, si le besoin s'en fait sentir.

En cas de besoin, continuez sur la voie de la simplicité. Choisissez un modèle, une bibliothèque ou un autre outil qui vous permettra d'écrire du code propre, simple et lisible qui fera le travail.

+1

ne peut pas dire combien de fois tout au long de la journée, je dis cela. – Tigran

0

Les deux types et vos IdentificationCriteria IdentificationCriteriaAnalyzer me regarde un peu comme Specifications, donc je voir s'il est logique de les factoriser dans cette direction.

La classe IdentificationRequest me semble rompre le Single Responsibility Principle - pourquoi a-t-elle un champ/une propriété Person? L'API pourrait également bénéficier d'un meilleur Command-Query Separation.

Donc, je pense qu'un meilleur modèle serait de définir une interface qui prend un IdentificationCriteria et retourne une sorte de Command. Une telle interface serait essentiellement Abstract Factory.

public interface IIdentificationCommandFactory 
{ 
    IIdentificationCommand Create(IdentificationCriteria spec); 
} 

Lorsque vous implémentez, vous pouvez rechercher des correspondances dans votre repostiry, et en fonction du résultat de cette requête et vos autres caractéristiques (comme le IdentificationCriteriaAnalyzer), vous pouvez retourner la mise en œuvre correcte de IIdentificationCommand.

L'appelant demande alors à la commande retournée de s'exécuter.

+0

La propriété IdentificationRequest contient une propriété Person, car la propriété IdentificationRequest est conservée et, dans la table db, elle a ensuite un ID pour la personne à laquelle elle a été attribuée. Pourriez-vous s'il vous plaît poster un exemple plus complet sur la façon dont vous implémenter le modèle de commande? – Chris

0

Il me semble que vous devriez utiliser le modèle de commande:
- http://www.dofactory.com/Patterns/PatternCommand.aspx
- http://c2.com/cgi/wiki?CommandPattern
- http://en.wikipedia.org/wiki/Command_pattern

Aussi votre IdentificationRequest ne se sent pas comme un entity class, mais je qualifierais votre personne classe en tant qu'entité.
Souvent, l'Invoker dans le Motif de Commande envoie une réponse au destinataire, indiquant le succès ou l'échec, et en cas de succès, l'objet de réponse peut contenir le namedPerson.

+0

Salut, merci. IdentificationRequest est une entité car elle est conservée dans la base de données. Si aucune identification automatique n'a pu être faite, une interaction humaine ultérieure avec cette demande est requise. Ensuite, si une personne est identifiée, un employé peut affecter cette personne à IdentificationRequest. – Chris

Questions connexes