2009-03-02 10 views
3

Je veux savoir s'il existe un modèle de conception pour spécifier des options à un ensemble d'algorithmes. J'utilise C++. Permettez-moi de décrire mon problème. J'ai un ensemble d'algorithmes et ces algorithmes ont différentes options. Je veux concevoir un accès unique à ces algorithmes. Quelque chose de similaire à un schéma de stratégie. Cet accès à point unique est une classe de contrôleur qui prend en entrée une classe d'options génériques. Selon les options, un algorithme approprié sera utilisé. Je veux généraliser ces options afin que je puisse étendre les algorithmes et le client. Merci, AmolConception d'options génériques pour les algorithmes

Répondre

2

bâtiment sur Konrad's suggestion of using policy types, si vos algorithmes nécessitent des paramètres au moment de la construction, vous pouvez gérer cela proprement en exigeant que toute la classe Policy a un type imbriqué appelé Params, puis fournir un constructeur à l'intérieur fancy_algorithm<Policy> qui prend un argument de ce type et il passe au contenu Policy objet:

template <typename Policy> 
class fancy_algorithm : private Policy { 
public: 
    typedef typename Policy::Params Params; // Need to redeclare :(

    explicit fancy_algorithm(Params params = Params()) : Policy(params) {} 
}; 

Tous les paramètres pertinents doivent être emballés dans un seul objet de type Policy::Params.

La classe Policy est toujours construite avec un seul argument de type Policy::Params. Pour travailler avec des classes de règles qui ne requièrent aucun paramètre, fournissez un constructeur par défaut (ou utilisez celui implicitement déclaré) dans Params, pas dans Policy. De cette façon, en utilisant une valeur par défaut pour le constructeur fancy_algorithm<Policy> comme ci-dessus, nous activons par défaut construction pratique d'un fancy_algorithm<Policy> chaque fois que Policy::Params a un constructeur par défaut (à savoir lorsque le Policy ne nécessite pas de paramètres). Aucune sécurité est perdue: si un constructeur Policy::Params manque par défaut (ce qui indique que certains paramètres sont nécessaires ), toute tentative par défaut-construire un objet fancy_algorithm<Policy> échouera au moment de la compilation.

Exemple:

struct multiply_by_params { 
    multiply_by_params(int x /* = 42 */) : _x(x) {}  // See bottom 
    int get() const { return _x; } // Or, just make multiply_by a friend 

private: 
    int _x; 
}; 

struct multiply_by { 
    typedef multiply_by_params Params; 
    multiply_by(Params p) : _x(p.get()) { /* Other initialisation */ } 

    // Other code implementing the strategy (e.g. an operator()()) 
    ... 

private: 
    int _x; 
}; 

fancy_algorithm<multiply_by> a(69); // Always compiles 
fancy_algorithm<multiply_by> b;  // Compiles iff /* = 42 */ is uncommented 
+0

Cela m'a amené à réfléchir plus sérieusement aux classes de politiques. Merci –

+0

De rien Amol :) –

7

Un motif souvent utilisé est de créer une classe politique qui est passée comme un type de modèle à votre classe, puis héritée de privé:

template <typename Policy> 
class fancy_algorithm : private Policy { 
}; 

Un célèbre exemple est la std::allocator classe qui est souvent hérité de cette manière:

template <typename T, typename Alloc = std::allocator<T> > 
class my_container : private Alloc { 
public: 
    typedef Alloc allocator; 

    // It's necessary to make the base class names available explicitly. 
    typedef typename allocator::pointer pointer; 

    using allocator::construct; 
    // … 
}; 
+0

Intéressant! Au début, j'ai pensé: Pourquoi en tirer? Ce n'est pas une relation is-a. Mais à la réflexion, cela a du sens: nous héritons tous les getters/setters pour les options, ce qui est très pratique, donc nous pouvons les définir de l'extérieur. – Frank

+0

@dehmann: Oui, c'est contre-intuitif. Cependant, l'héritage privé ne modèle pas les relations «est-a», mais plutôt «est-implémenté-en-termes-de». L'héritage privé en lui-même est un concept très confus car il n'est pas du tout lié à l'héritage public *. Fondamentalement, l'héritage privé est ... –

+0

(suite): ... juste une notation de commodité pour l'appartenance privée dans une classe (composition). Ne l'utilisez pas, sauf dans des cas étranges comme ci-dessus. C'est un cas particulier car il est devenu un idiome du langage et de nombreux auteurs de bibliothèques C++ savent immédiatement ce que cela signifie dans ce contexte. –

Questions connexes