2011-05-24 2 views
1

Faisons un exemple simple. Supposons que j'ai une collection d'objets Number, qui peut alors être même ou impaire. Supposons que je souhaite parcourir cette collection et traiter chaque élément. Le processus dépend du type d'élément: même ou impair.Comportement différent en fonction des données

Exemple: Imprimer chaque élément, tel que:

  • si Number est encore, je "Ceci est un nombre pair."

  • Si Number est impair, j'ai "Ceci est un nombre impair."

Cependant, je peux décider plus tard que je veux pour seulement les nombres pairs d'imprimer « un nombre pair. »

Alors, comme nous le voyons, cela pourrait être résolu avec héritage et Polymorphisme, grâce à l'utilisation de fonctions virtuelles:

class Number {/*...*/};    // base class 
class Even : public Number {/*...*/} // derived class 
class Odd : public Number {/*...*/} // derived class 

Cependant, comment puis-je fournir la flexibilité dans le processus de exécuter un comportement différent plus tard, comme indiqué dans l'exemple ci-dessus? Aussi, y a-t-il une alternative à l'héritage et au polymorphisme? Parce que je n'ai pas voulu créer d'arbre d'héritage uniquement à cause d'un calcul/processus spécifique. Le problème original consiste à exécuter un modèle mathématique différent en fonction du type d'objet, et le modèle mathématique n'est pas unique pour un type donné d'objet (la façon dont je peux imprimer le nombre pair n'est pas unique).


Edit: Il est drôle que ce poste a été fermé avec l'argument selon lequel il est difficile de dire ce qui est demandé. Les auteurs des plusieurs réponses ci-dessous ne semblent pas d'accord avec cela, puisque tous pourraient le comprendre et répondre à ce que je cherchais.

+0

On ne sait pas ce que vous demandez. L'exemple n'a pas de sens. 'Even' et' Odd' ne sont pas de très bons types ou sous-classes de données. Personne ne créerait ces classes pour résoudre ce problème (print "Ceci est un nombre (pair/impair)"). Vous devez également spécifier quel type de flexibilité vous souhaitez exécuter différemment "plus tard". –

+2

Certains pourraient le faire s'ils essayaient de sous-estimer les stratégies. –

Répondre

2

Vous pouvez séparer votre hiérarchie Strategy des numéros réels. De cette façon, il n'y a pas besoin d'une hiérarchie de classes artificielle, et vous êtes libre de changer les associations entre les types de nombre (valeur) et les actions, même à l'exécution. L'association peut être définie

  • si vous vous en tenez à la hiérarchie de classe Number, puis entre la sous-classe Number (Odd, Even) et la classe de stratégie (OddNumberStrategy, EvenNumberStrategy), ou
  • par une correspondance entre des valeurs concrètes et stratégie instances (bien sûr, cela ne convient que si vous avez relativement peu de valeurs concrètes), ou
  • par une fonction de sélection.

Comme une approche alternative, vous pouvez redéfinir vos stratégies comme gestionnaires, chacun peut décider si une valeur donnée convient pour eux de gérer et de les traiter le cas échéant. De tels gestionnaires pourraient même être enchaînés ou stockés dans une collection (et ensuite itérés pour chaque valeur), de sorte que certaines valeurs peuvent être traitées par plusieurs gestionnaires «chevauchants», si cela vous convient.

+0

Le schéma de stratégie est ce dont j'ai besoin et votre réponse reflète très bien mon problème. Je ne veux pas créer de hiérarchie de classe juste à cause d'un processus spécifique parmi beaucoup d'autres. Merci. – Allan

3

Eh bien, vous pouvez utiliser un Strategy pattern: avoir deux classes EvenStrategy et OddStrategy, mettre le comportement en eux, et ajouter ensuite aux paires et impaires des classes à ORM de construction lorsque vous les insérez dans la collection.

2

Il existe plusieurs façons de résoudre cela, mais en général, ils utilisent tous composition. Prenons votre exemple. Disons que nous avons un tableau d'entiers:

int foo[] = {0,1,2,3,4,5,6,7,8,9}; 

Maintenant, nous voulons imprimer tous les nombres impairs de ce:

void printIfOdd(int number) { 
    if(number % 2 == 1) 
     std::cout << number << std::endl; 
} 

std::for_each(foo, foo+10, printIfOdd); 

On pourrait faire la même chose pour les nombres pairs. Si vous souhaitez imprimer à la fois, vous pouvez composer les fonctions (qui dans ce cas est pas dans le sens mathématique de la composition de fonction):

template<class T> 
class apply_all_functor { 
public: 
    apply_all_functor(T f1, T f2) : f1(f1), f2(f2) {} 

    void operator()(int number) { 
     f1(number); 
     f2(number); 
    } 
private: 
    T f1, f2; 
}; 

template<class T> 
apply_all_functor<T> apply_all(T f1, T f2) { 
    return apply_all_functor<T>(f1, f2); 
} 

std::for_each(foo, foo+10, apply_all(printIfOdd, printIfEven); 

L'idée de la composition peut naturellement être également étendu à des objets, ce qui donne passer à des modèles comme le Strategy-Patter et le Decorator-Pattern. Vous pouvez voir tous les exemples du code here.

Questions connexes