2010-02-18 4 views
0

Je crée une classe de boutons et j'ai du mal à choisir entre deux solutions.Modèles et hiérarchie d'actions

1) Templacer la classe Button et lui demander de prendre un objet fonction dans son constructeur pour l'appeler lorsque le bouton est enfoncé. Le gars avec qui je suis en train de coder s'inquiète que cela conduise à un gonflement du code.

2) Créez une classe de base ButtonAction, et il y aura une ButtonAction différente pour chaque bouton. Ainsi, la classe Button prend une ButtonAction dans son constructeur pour appeler lorsque le bouton est enfoncé.

Nous avons également envisagé l'utilisation de pointeurs de fonction, mais nous n'y avons pas réfléchi de manière approfondie.

+0

deux sont des solutions acceptables. De quel genre de critères vous inquiétez-vous? La deuxième forme pourrait être un peu plus lisible mais certainement plus verbeuse. Vous pouvez réaliser la première solution sans modèles je crois. – Pace

Répondre

5

Vous pouvez utiliser des objets boost::function<> pour vos actions. De cette façon, vous ne avez pas besoin de modèles et la classe bouton devient très flexible:

struct Button { 
    typedef boost::function<void()> action_t; 
    action_t action; 

    Button(const action_t &a_action) : action(a_action) { 
    } 

    void click() { 
     action(); 
    } 
}; 

De cette façon, la classe est facile à utiliser avec des pointeurs de fonction, objets de foncteurs ou des choses comme boost::bind:

void dosomething(); 
Button b1 = Button(&dosomething); 

struct SomeAction { 
    void operator()() {} 
}; 
Button b2 = Button(SomeAction()); 
+1

+1, considérez également que dans de nombreux frameworks, vous pouvez connecter plus d'une action à un seul bouton. Si vous voulez fournir cette fonctionnalité à un moment ou un autre, vous avez juste besoin de changer votre type interne 'boost :: le signal ' 'et appeler .connect' au lieu d'assigner l'action à la fonction' boost :: <> ' objet –

1

Je voudrais énumérer les conséquences de chaque alternative, puis décider quelle option est la meilleure pour le cas particulier à portée de main.

Si l'option de modèle peut (prématurément?) Gonfler le code objet, l'alternative de polymorphisme peut rendre le code source inutilement complexe.

Dans le cas des modèles, le compilateur créera une autre classe Button pour chaque objet fonction avec lequel vous l'instanciez. Cela signifie que le code d'objet du produit sera plus grand que si vous avez une seule classe Button qui accepte divers objets d'action via une sous-classe. Dans le cas du polymorphisme, le compilateur générera une seule classe Button mais vous aurez maintenant une autre classe de base à maintenir, et vous serez obligé de la sous-classer pour toute nouvelle action que vous ajouterez à votre collection. En particulier, vous ne pourrez pas utiliser les actions qui ont été écrites avant de créer la classe d'action de base, sauf si vous pouvez les modifier afin qu'elles dérivent de cette classe d'action.

L'alternative de modèle vous permet d'utiliser tout ce qui est conforme à l'interface du modèle. Donc, si vous utilisez le paramètre template en tant que fonction, vous pouvez accepter tout ce qui peut être appelé comme une fonction. Cela implique que vous n'avez même pas besoin de considérer l'alternative des pointeurs de fonction, puisque les modèles vous permettent d'accepter des pointeurs de fonction - et bien plus encore.

L'option de polymorphisme implique que le compilateur en sait plus sur ce que vous essayez de faire. En d'autres termes, les modèles sont livrés avec des erreurs de modèles.

Vous pouvez atténuer certains des problèmes de modèle si vous pouvez trouver un moyen de modéliser uniquement les fonctions membres Button, plutôt que la classe Button entière. Prenez comme paramètre de fonction une instance du modèle, vous n'avez donc pas besoin d'instancier explicitement la fonction du modèle. Ensuite, vous gagnez à la fois sur certains des avantages du modèle ainsi que certains des avantages du polymorphisme.