2010-11-15 40 views
5

J'ai un ensemble de classes, dont chacune doit décider à un moment ou l'autre de deux ou trois approches à utiliser en interne pour implémenter la même fonctionnalité de manière externe. Idéalement, ceci devrait inclure une fonctionnalité de repli, où si ApproachA échoue, il échoue pour essayer ApproachB (et peut-être approche C, D, etc.). Jusqu'à présent, je viens d'utiliser le codage comme if (!success) { ApproachB code }. Le problème avec ceci est que plusieurs méthodes ultérieures doivent également être conscientes de l'approche qui a été choisie et toutes développent également leurs propres instructions. Je veux vraiment résoudre le problème avec quelque chose de moins lourd ... sauf qu'aucune des autres options que j'ai considérées ne semble être «maniable». Voici les trois approches auxquelles j'ai pensé:Implémentation de classes "de repli"

  1. Implémentez une méthode .Create statique qui détermine laquelle des deux classes dérivées à créer, où les deux classes ont une interface qui les sauvegarde. L'inconvénient de ceci est que vous écrivez beaucoup deux fois le même code, et que cela ne crée pas vraiment de "repli", car cela oblige à prendre toutes les décisions à l'avance dans la méthode .Create. Cela devrait fonctionner 9/10 fois, mais il y aura l'autre 1/10 fois où je veux que le repli ne démarre que lorsque le primaire a essayé et échoué.
  2. La même chose que ci-dessus, mais avec une classe de base ou abstraite impliquée, soit comme classe de support pour les deux, soit avec la classe primaire comme classe de base pour le repli. Cela a le même désavantage de repli, mais au moins il y a peu ou pas de code répété.
  3. une classe abstraite Mettre en oeuvre normalement construit avec des classes d'enfants qui peuvent être modifiés à l'exécution: à savoir

    public void SomeMethodOrConstructor() 
    { 
        if (someConditions) 
         MyChild = ChildClassA; 
        else 
         MyChild = ChildClassB; 
    } 
    
    
    public void Execute() 
    { 
        MyChild.Execute(); 
    } 
    

Le problème avec l'option 3 est le passage de données entre les deux en cas de besoin. Puisque certaines de ces méthodes modélisent des objets extérieurs, cela sera assez fréquent. Les classes imbriquées partagent-elles automatiquement les données avec leur classe parente? Ou devrais-je passer le tout à chaque appel?

Autre chose que je devrais considérer?


Mise à jour: La première classe est opérationnelle avec la chaîne de responsabilité. Pour l'instant, j'ai choisi de ne pas utiliser le pattern de stratégie ou le repli pendant l'exécution de la méthode, car je pense que cela peut être inutile à la fin. Je pense que la plupart de ces solutions de repli seront meilleures en restant dans leurs propres classes, car il n'y aura pas de changement complet de plan de jeu, juste quelques modifications mineures à faire. Si cela s'avère ne pas être le cas, je sais au moins ce dont j'ai besoin d'enquêter maintenant.

Merci à tous ceux qui ont contribué à la solution ultime!

Pour les curieux, ma solution ultime travaillé à peu près comme ceci:

  • Créer Handler classe abstraite, à peu près comme indiqué dans l'article de Wikipedia, mais avec une fonction public abstract Handler GetHandler(), et en ajoutant d'autres méthodes abstraites comme la charge, Enregistrer, etc.
  • Implémenter des sous-classes de gestionnaire privé pour la classe parente (elles pourraient aussi bien être des sous-classes, puisqu'elles ne traiteront que des choses pour cette classe particulière ... évite aussi les problèmes de nommage ultérieurs). Les classes enfants prennent toutes un paramètre du type de l'objet parent dans leur constructeur, ce qui leur permet d'accéder facilement aux données du parent.À partir du constructeur de la classe parente, configurez les gestionnaires/successeurs de la chaîne de responsabilité (encore une fois, comme dans l'exemple), puis appelez le FirstHandler.GetHandler(this) et stockez le résultat pour que la classe sache quel gestionnaire utiliser dans le futur.
  • La plupart des méthodes manipulées se réduisent simplement à.
+2

Vous pouvez placer du code dans une liste numérotée en l'indentant avec _eight_ spaces. – SLaks

+0

Merci pour le conseil de mise en page, qui me conduisait au mur! – RobinHood70

Répondre

5

Utilisez Chain of Responsibility. motif

chaîne de responsabilité est un modèle de conception constitué d'une source d'objets de commande et une série de objets de traitement. Chaque traitement objet contient un ensemble de logique qui décrit les types d'objets de commande qu'il peut traiter, et comment faire passer ceux qu'il ne peut pas traiter à la prochaine objet de traitement dans la chaîne. Un mécanisme existe également pour ajouter de nouveaux objets de traitement à la fin de cette chaîne .

Ceci correspond parfaitement à ce que vous devez faire.

+0

Je vais jouer avec cet après-midi, mais je suis sûr que c'est la réponse que je cherchais! – RobinHood70

+0

Tout, donnez moi un cri. – Aliostad

+0

Des conseils sur la façon de mettre en œuvre cela en termes d'appels ultérieurs? Pour placer mon cas spécifique dans un exemple plus générique, supposons que j'ai des méthodes Load and Save, où Load gère les fichiers XML ou TXT. Enregistrer n'a pas besoin de "re-comprendre", Load a déjà déterminé ce qu'il gère. Je pense que la classe parent doit juste avoir une propriété Handler qui indique quel gestionnaire a finalement géré l'événement, mais je ne suis pas sûr de la meilleure façon de l'implémenter. – RobinHood70

0

Je pense que vous avez besoin Task/Task<T>, en particulier la méthode ContinueWith(Action<Task>) et 4 propriétés: IsCanceled, IsCompleted, IsFaulted et Result.

1

J'utiliserais probablement le modèle de stratégie ici.

http://en.wikipedia.org/wiki/Strategy_pattern

Vous avez seulement besoin de passer au lieu des classes Biographie des délégués entiers. Si toutes les méthodes utilisent les mêmes informations pour le traitement, cela peut être utile.

+0

Ceci est également une bonne solution, mais si je comprends bien, il n'aurait pas le comportement attendu que je cherchais. – RobinHood70

+0

On dirait que votre modèle de stratégie entre en jeu après tout. :) Merci! – RobinHood70