2009-11-14 12 views
2

Nous travaillons sur un projet de traitement d'image utilisant C# et EmguCV. Notre équipe est composée de 3 personnes. Pour progresser plus rapidement, nous travaillons tous les trois sur différents sous-problèmes ou expérimentons différents algorithmes en même temps.Modèle de stratégie - types/valeurs de retour multiples

Actuellement, chacun d'entre nous crée une fonction qui contient le code majeur sur lequel nous travaillons et chacun d'entre nous apporte des modifications au pilote pour ajouter des appels à nos nouvelles fonctions. Tout cela se passe sur le même fichier. Nous utilisons le contrôle de source, donc nous ne sommes pas encore entrés dans les autres orteils. Mais je ne pense pas que cela sera durable car nous faisons plus de progrès. En outre, je pense que le code devient de plus en plus désordonné. Je pensais qu'il serait peut-être mieux pour nous d'implémenter le pattern Strategy et d'encapsuler nos algorithmes ou sous-problèmes dans des classes qui leur sont propres et d'appeler la méthode execute sur chacun d'eux depuis le driver.

Cependant je me rends compte qu'il peut y avoir quelques problèmes avec cette approche:

  1. différents algorithmes prennent différentes entrées (image source, certains ensembles de paramètres différents, etc.)
  2. algorithmes retour sorties différentes (nouvelle image, jeu de fonctionnalités, une matrice, etc.)

Le premier problème, je crois que je peux surmonter en faisant quelque chose comme ça

Class Strategy1 : IStrategy 
{ 
    int _code; 

    // Different *input* paramteres for the strategy may be passed in the 
    // constructor depending on the type of strategy 
    public Strategy1(int c) 
    { 
     _code = c; 
    } 

    // This is the method defined in the IStrategy interface 
    public void execute() 
    { 
     // Some code that uses _code and does some processing goes here 
    } 
} 

Je peux changer les constructeurs pour les différentes stratégies afin qu'ils puissent prendre différents types d'arguments. Quand je pense à la façon de gérer le problème du retour de plusieurs types/valeurs, la première chose à laquelle je peux penser est de changer le type de retour d'exécution de void à quelque chose comme une table de hachage, où les différents paramètres de retour peuvent être stocké et retourné OU avoir d'autres membres de la classe, comme "int _returnCode" qui peut être récupéré par une autre méthode ou par le biais de propriétés en lecture seule de cette classe.

Je ne suis pas sûr de savoir quelle serait la solution en termes de principes de conception, et je serais heureux de connaître votre opinion là-dessus. Merci

+3

Si les stratégies sont si différentes les unes des autres - devraient-elles implémenter la même interface? – dtb

+1

Je suis d'accord avec DBT. Voir http://en.wikipedia.org/wiki/Interface_segregation_principle – TrueWill

+0

Quand vous dites que les algorithmes renvoient des choses différentes, est-ce que chaque algorithme renvoie une et une seule chose de types différents, ou plusieurs choses, certaines communes? Si vous n'avez aucun point commun entre ce que les implémentations retournent, il ne semble pas que le pattern Strategy soit correct. – Mathias

Répondre

0

Il y a plusieurs choses ici:

  • ayant tout dans un seul fichier est un anti-modèle « boule Big de boue »
  • Vous pouvez le diviser en plusieurs fichiers en utilisant des classes partielles, cela résoud votre problème de beaucoup de gens travaillant sur le même fichier, mais n'est que légèrement mieux. Au lieu du modèle de stratégie, pourquoi ne pas simplement créer des classes auxiliaires (modèle d'aide), chaque assistant peut être testé.
0

Si vous avez la liberté d'utiliser C# 4, vous pouvez compter sur la fonctionnalité de type retour covariant. De cette façon, vous pouvez définir l'interface pour exécuter comme:

public object execute() 

puis la remplacer dans les classes dérivées des types spécifiques de retour à cette classe concrète.

+0

C# 4.0 ne supporte pas les types de retour covariant. http://stackoverflow.com/questions/1723648 – dtb

+0

OK, si Eric Lippert le dit, ça doit être vrai. –

4

Si la seule chose que les algorithmes ont en commun est qu'ils s'exécutent, vous devriez penser au command pattern plutôt qu'au modèle de stratégie. (Au moins, cela correspond mieux à la solution que vous avez décrite.)

C'est très bien! Il ne vous achète pas le caractère durable du modèle de stratégie, mais il ne semble pas que vous soyez en mesure de le faire. Le modèle de commande vous permettra de garder votre code spécifique à l'algorithme séparé de votre contrôle de flux de traitement (le pilote, à partir du son de celui-ci).

Par exemple, il vous permettra d'écrire du code comme ceci:

// ... logic to obtain an image and handle application flow ... 

// I'm using 'image' here as a stand-in for a single object all your commands 
// could derive their inputs from, or a container of all the inputs. If no such 
// object exists, just do what you have to construct the commands. 
ICommand[] commands = ImageCommandFactory.CreateCommands(image); 

foreach(ICommand command in commands) { 
    command.Execute(); 
} 

// ... Handle commands ... 

Comme vous l'avez mentionné, les objets de commande utiliseraient des membres du public pour exposer les résultats de leur exécution - la forme la plus simple utiliserait une propriété comme public object Results { get; } . (Bien sûr, plus vous pouvez réduire cette valeur de retour à un type standard ICommandResults, mieux vous serez.)

La façon de gérer les résultats dépend de vous. Vous pouvez utiliser une usine (à nouveau) pour créer un gestionnaire approprié pour la commande que vous passez:

// Picks the correct type of processor, depending on the command 
IResultHandler handler = ResultHandlerFactory.CreateHandler(command, form); 

// renders the results to the form provided to the factory method 
handler.RenderResults(); 

Ou utilisez une autre technique qui convient le mieux à votre conception.

+0

@Jeff: Merci pour votre réponse. Je pense que je peux penser à chaque "processus" qui est fait en tant que commandes. Comment est-ce que je passerais plusieurs paramètres (je passerais non seulement l'image de source, mais quelques paramètres liés à la commande - par exemple au niveau de flou) aux commandes dans ce modèle? Je ne comprends pas très bien pourquoi vous utilisez ImageCommandFactor dans le premier exemple de code. Pouvez-vous s'il vous plaît expliquer. – Aishwar

+0

[suite] @Jeff: Si les résultats ne sont pas rendus (les résultats seront générallement utilisés dans un autre "processus", seulement à la fin de tous les processus, un résultat pouvant être rendu), y aurait-il raison d'implémenter des classes de résultats qui héritent de IResultHandler? – Aishwar

+0

@aip - l'usine est juste un moyen d'encapsuler la logique conditionnelle pour spécifier quels paramètres appartiennent à quelle commande. L'idée est que vous lui transmettez suffisamment d'informations pour générer toutes les commandes/algorithmes (en supposant que c'est ce que vous voulez faire). En ce qui concerne les résultats, je veux dire pour la méthode handler.RenderResults pour représenter tout processus que vous pourriez faire ensuite. Puisque vous effectuez un traitement supplémentaire avant de rendre quoi que ce soit, vous pouvez chaîner plusieurs commandes ensemble ou simplement le faire dans la commande d'origine. –