IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Pattern fabrique et dynamic_cast : question !


Sujet :

C++

  1. #1
    Membre confirmé
    Inscrit en
    Avril 2008
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 95
    Par défaut Pattern fabrique et dynamic_cast : question !
    Bonjour,

    Je développe une petite librairie de classes génériques que je réutiliserai dans mes projets, dans laquelle j'incorpore une classe "Fabrique" (du design pattern du même nom) à l'aide de templates. D'ailleurs, elle est très fortement inspirée du cours de developpez.com :
    http://come-david.developpez.com/tut...e=Fabrique#LIV

    Je n'ai pas trouvé d'autre moyen que de dériver ma classe Factory<Operation> (par exemple) en :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    OpFactory* factory = dynamic_cast<OpFactory*>(OpFactory::instance());
    où la classe OpFactory dérive bien sur de Factory<Operation> et Factory<Operation> est implémentée sous forme de singleton.

    Je ne suis pas un fin connaisseur des casts, mais j'en sais assez pour savoir qu'il faut se méfier de ce genre de pratique. La preuve par 3 après 2 secondes de recherche :
    http://cpp.developpez.com/faq/cpp/in...RS_downcasting

    Aussi, je voudrais savoir s'il y a un moyen plus sioux d'étendre la Factory avec template ?

    Merci d'avance pour vos réponses !

  2. #2
    Membre chevronné
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Par défaut
    Je comprend pas pourquoi tu upcast ton OpFactory* en Factory<Operation> si tu comptes le re-downcast plus tard ?

    Gardes simplement ton OpFactory* de quand tu le crées.

    A moins que tu veuilles faire une liste de Factory différents et que tu veuilles tous les gérer pareil.

    Là tu peux tout mettre dans des listes/vector différents selon leur type et ensuite d'upcaster si tu dois le faire (par exemple pour certaines méthodes qui ne prennent que des Factory<Operation>).

    Ton problème c'est d'upcast des objets sans garder trace de ce qu'ils sont en vrai et d'avoir à recourir à un downcast par la suite.

  3. #3
    Membre confirmé
    Inscrit en
    Avril 2008
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 95
    Par défaut
    Salut,

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    OpFactory* factory = dynamic_cast<OpFactory*>(OpFactory::instance());
    En fait la hiérarchie des classes est la suivante :
    - classe Singleton<T>
    - classe Factory<Key, Object*> dérivée de Singleton < Factory<Key, Object*> >

    La dérivation de Singleton permet d'utiliser instance() et de gérer l'instance unique de la classe Factory<Key, Object*> dans la classe Singleton.

    La classe Factory<string,Operation*> gère la fabrication d'objets "Operation" par clonage. Tout cela fonctionne comme il se doit jusqu'ici :
    - instanciation unique et facile de la Factory
    - enregistrement et création transparente pour l'utilisateur d'objets "Operation" par la Factory

    Seulement le problème est que je souhaiterai créer grâce à ce "framework" si j'ose l'appeler ainsi, des classes dérivées de "Operation". Disons "TailOperation" pour l'exemple.

    Aussi, je dérive Factory<string, Operation*> en OpFactory qui a une méthode "createTailOperation" qui devrait dans l'esprit appeler la methode "create" de la classe de base pour cloner le prototype (enregistré au préalable) de TailOperation puis éventuellement effectuer quelques initialisations.

    Or, si j'appelle "create" de Factory<string, Operation*> je me retrouve bien avec une instance de Opération. Pour manipuler les fonctions de la classe dérivée TailOperation je ne vois pas comment faire d'autre qu'un dynamic_cast ?

    Bref, je m'y PERD !

    Help please !

  4. #4
    Membre chevronné
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Par défaut
    Tu ne dois pas garder ton OpFactory en tant que Factory< string, Operation* >.

    Gardes le toujours en tant que OpFactory, de cette manière, tu pourra appeller tailOperation.

  5. #5
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,
    Un peu de code permettrait peut être de clarifier la chose.
    J'ai d'abord penser à un retour co-variant mais je ne sais pas si cela convient à ton architecture.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    class A{};
    class A_spec : public A{};
     
    class Factory
    {
    public :
       virtual A* create_A();
    };
    class Factory_spec
    {
    public:
       virtual A_spec create_A();
    };
    Peux-tu montrer un bout de code sur ta factory et sa spécialisation, là où tu voulais faire un downcast ?

  6. #6
    Membre confirmé
    Inscrit en
    Avril 2008
    Messages
    95
    Détails du profil
    Informations forums :
    Inscription : Avril 2008
    Messages : 95
    Par défaut
    Merci pour vos réponses. Elles indiquents que le problème n'est pas au niveau "Factory<A,B> ou OpFactory" VS "Operation et tailOperation" mais plutôt au niveau du dessus (niveau au sens de la hiérarchie des classes) : la Factory<A,B> dérive de Singleton<Factory<A,B>. Aussi lorsque je fais :
    j'obtiens systématiquement une Factory<A,B>. D'où le besoin de downcast pour récupérer OpFactory ...
    Voici les parties du codes qui semblent donc poser problème:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template<class T> class Singleton
    {
    public:
        static T* instance();
        static void kill();
    private:
        static T* _instance;
    protected:
        Singleton();
        virtual ~Singleton();
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template<class Object, class Key = std::string> class Factory : public Singleton<Factory<Object, Key> >
    {
        friend class Singleton<Factory>;
    public:
        static void registerObject(Key key, Object* obj);
        Object* create(Key key);
    private:
        Factory();
        virtual ~Factory() {}
    protected:
        static std::map<Key,Object*> _map;
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    class OpFactory : public Factory<Operation>
    {
    public:
        TailFileOperation* createTailFileOperation(const QString& file, int interval);
    private:
        TailFileOperation* _prototypeTailFile;
    };
    Et le main que j'aimerais pouvoir réaliser :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    // 1. Instanciation d'une OpFactory comme un singleton
    OpFactory* factory =OpFactory::instance();
    // => Erreur : instance renvoie une Factory<A,B> :(
    // A l'heure actuelle le code qui fonctionne est celui avec un downcast :
    // OpFactory* factory = dynamic_cast<OpFactory*>(OpFactory::instance());
     
    // 2. Enregistrer via la classe prévue à cet effet dans Factory<Operation*,Key> un objet :
    // => OK car TailFileOperation dérive de Opération
    factory->registerObject("tail", new TailFileOperation);
     
    // 3. Utiliser un méthode de OpFactory, spécifique à la classe gérant l'instanciation 
    // (par clonage de prototype) puis l'initialisation d'un objet TailFileOperation :
    // => OK car l'objet "factory" pointe sur une OpFactory, mais je le rappelle au prix du downcast 
    TailFileOperation* t = factory->createTailFileOperation("toto", 10);
    Une idée pour faire ceci en gardant le partage des responsabilités :
    - Singleton joue son rôle
    - Factory<A,B> fait office de fabrique ET de Singleton car dérive de Singleton<Factory<A,B>>
    - OpFactory n'a a se préoccuper de rien à part de objet qu'elle gère car elle hérite de Factory<A,B> qui hérite de Singleton<Factory<A,B>>

    Si ce n'est pas clair n'hésitez pas

    Merci d'avance

Discussions similaires

  1. [WD19] Pattern RAD en 2 questions
    Par R&B dans le forum WinDev
    Réponses: 4
    Dernier message: 17/10/2014, 14h17
  2. Question sur les pattern fabriques
    Par oukacha dans le forum ALM
    Réponses: 1
    Dernier message: 31/05/2012, 12h44
  3. [Débutant] question sur dynamic_cast
    Par Higestromm dans le forum C++
    Réponses: 4
    Dernier message: 18/05/2006, 16h26
  4. [Design]Question sur le pattern Controleur.
    Par sebastieng dans le forum AWT/Swing
    Réponses: 5
    Dernier message: 06/03/2006, 18h36
  5. [GOF] [Fabrique Abstraite] [Pont] Questions ?
    Par manel007 dans le forum Design Patterns
    Réponses: 5
    Dernier message: 04/01/2005, 20h18

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo