2012-06-19 6 views
0

À l'heure actuelle, j'ai un client qui envoie une liste de commandes à mon serveur dont il veut des données. Mon serveur charge ces commandes via une DLL à l'aide GetProcAddress, par exemple:Modèle de conception de rappel

InitializeDLL initializeDLL = (InitializeDLL)GetProcAddress(hInstanceLibrary, "InitializeDLL"); 

où initiailizeDLL est défini comme:

typedef int (CALLBACK* InitializeDLL)(int,int); 

Le bon client envoie maintenant le nom de la commande comme une chaîne pour laquelle il veut des données pour. J'ai toute une liste de commandes que j'aimerais pouvoir utiliser, et je n'ai pas d'idée sur la façon de l'implémenter de manière efficace. Je pensais à créer une carte et en utilisant la chaîne pour le nom comme une clé, puis le CALLBACK * pour la fonction appropriée comme un pointeur. Mais alors je devrais aussi le jeter après. Je suis principalement un programmeur Java, et pas le meilleur programmeur C++, donc je ne suis pas sûr que cette idée de Map fonctionnera même ou comment gérer le casting à la fin. En outre, j'ai regardé le modèle de commande sur Wikipedia, mais je ne sais pas comment cela serait mis en œuvre dans ce cas.

+0

'l'aide d'une carte <>' ne semble pas être une mauvaise idée. Essayez-le, et si vous rencontrez des problèmes, vous pouvez revenir et poser des questions différentes. La bonne chose à propos des conteneurs STL est qu'il est relativement indolore de les remplacer par un autre, tant que vous «typedef» le conteneur. – jxh

+0

Est-ce que tous les pointeurs de fonction auront la même singularité? – Brady

+0

La plupart des pointeurs de fonction sont similaires, bien qu'un couple renvoie double au lieu de int et le nombre de paramètres peut varier. –

Répondre

0

Une carte devrait être bien pour faire cela. Une carte qui mappe chaque chaîne à un pointeur de fonction qui s'exécutera lorsqu'un certain message est reçu. Si vous voulez aller le modèle de commande, vous pouvez avoir quelque chose comme: Désistement, je ne l'ai pas écrit du code C++ depuis des siècles, ce code pourrait ne pas compiler):

abstract class Command{ 
    private: 
    string commandName; 
    CALLBACK* callBackFunction 
    public: 
    Command(string name, CALLBACK* function){ 
     commandName = name; 
     callBackFunction = function; 
    } 
    // Here, you can check your current environment 
    // to see if you can execute this command in the current 
    // configuration and system state 
    bool CanExecute() = 0; 

    // This method does the call to the callback 
    void Execute(){ 
      // call the callback function here 
    } 
} 

Ce modèle est un mélange de la commande et modèles de méthode d'usine. Définissez les commandes qui héritent de la classe abstraite Command pour chaque entrée possible. Maintenant, au lieu d'avoir une carte de chaînes avec des pointeurs de fonction, vous pouvez avoir une carte de chaînes avec des commandes. Lorsque vous obtenez une chaîne, appelez d'abord CanExecute pour voir si la commande peut être exécutée dans l'état actuel. Appelez Execute pour exécuter votre commande dans laquelle vous appelez la fonction de rappel. C'est la meilleure façon de penser aux commandes d'encapsulation, à leurs conditions d'exécution et à leur code à exécuter.

Sur une note de côté, ce modèle est largement utilisé maintenant dans .NET (WPF)