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 :

Drole de fabrique


Sujet :

C++

  1. #1
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut Drole de fabrique
    Bonjour à tous,

    Je travaille actuellement sur une grosse lib de traitement d'images, qui repose entièrement sur le pattern fabrique. En fait, tous les objets sont instanciés à partir d'un fichier xml de configuration contenant le nom des classes à utiliser (c'est d'ailleurs un peu perturbant comme système).
    J'avais l'habitude de voir les fabriques sous la forme d'une classe de base offrant la fonction virtuelle clone(), avec insertion d'un objet de chaque classe dans une map<string,ClassPrototype*>.
    Cette lib offre un mécanisme un peu particulier basé sur les macro : toutes les classes utilisent la macro suivante dans leur déclaration:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    #define DECLARE_CLASS( __NAME__) \
          static ObjectInterface* create() \
             {\
                     return new __NAME__(); \
            }
    Une autre macro , REGISTER_CLASS(MaClasse):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    #define REGISTER_CLASS(__NAME__) \
    ObjectInterfaceFactory::instance().registerObject(QString(#__NAME__),__NAME__::create);
    permet d'enregistrer la classe dans ce qui semble être une map<string, pointeur de fonction >

    Il semble que l'utilité du système soit d'éviter l'instantiation d'un objet de chaque type (vu le nombre de classe, ça se justifie). Cette utilisation de la fabrique est-elle courante (Je l'ai également vu dans wxWidget) et pose-elle des problèmes de conception majeurs (faut aimer les macros)?

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    C'est très courant, et c'est même une meilleure solution car pour créer de nouveaux objets, on utilise une fonction plutôt qu'une instance bidon.

    Par contre l'intégration à base de macros n'est pas terrible, on peut faire ça beaucoup plus proprement.

  3. #3
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Citation Envoyé par vikki Voir le message
    permet d'enregistrer la classe dans ce qui semble être une map<string, pointeur de fonction >
    C'est exactement ce que je cherche présentement à faire, mais sans macro !
    Voir mes posts des derniers jours, si ça t'intéresse.

  4. #4
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Citation Envoyé par Laurent Gomila Voir le message
    C'est très courant, et c'est même une meilleure solution car pour créer de nouveaux objets, on utilise une fonction plutôt qu'une instance bidon.
    Si tu as des termes à donner pour effectuer une recherche sur Google, je suis preneur.
    Je rame, en ce moment... J'ai mis mon map en statique, et ça ne veut pas linker.

  5. #5
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Effectivement, s'il existe une solution simple sans macro (je vois pas bien comment s'en passer à par en insérant directement le code remplacé par leur utilisation ), je suis preneur^^

  6. #6
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    e rame, en ce moment... J'ai mis mon map en statique, et ça ne veut pas linker.
    Dans mon exemple la map est stockée en statique également (enfin je crois). T'es sur de l'avoir bien redéclaré dans le cpp?

  7. #7
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Et non... J'avais tellement la tête dans le guidon, et comme cette fabrique a présenté toute une série de problème, je ne me suis même pas posé la question de ce truc aussi simple. Je pensais que ça venait forcément de nouveaux territoires conceptuels que j'explorais !

    Relis mes post dans la section C++ et C++/Boost, et si tu veux t'inspirer de ce sur quoi je suis parti et que tu as besoin d'explications, n'hésite pas.
    Le seul truc qui me chagrine, c'est le transtypage explicite lors de l'ajout dans le map, et que je n'avais pas eu à faire quand j'ai fait un bout de code simpliste hors classe pour expérimenter ma fabrique.

  8. #8
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 518
    Points
    41 518
    Par défaut
    MFC fait ça avec des objets d'une classe donnée: Chaque classe contient une instance statique de CRuntimeClass, dont une des variables membres est un pointeur de fonction.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  9. #9
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Et c'est quoi cette solution sans macro ? Ca m'intéresse.
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  10. #10
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Tu t'adresses à moi, ou à Medinoc ?

  11. #11
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    à quiconque pouvant poster la réponse
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  12. #12
    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
    Points : 13 017
    Points
    13 017
    Par défaut
    A la place des macros, avez-vous essayé d'utiliser boost::assign? J'ai l'impression que cela pourrait résoudre le problème de remplissage de la map sans macro?

  13. #13
    Membre émérite
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 764
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 764
    Points : 2 704
    Points
    2 704
    Par défaut
    Citation Envoyé par mister3957 Voir le message
    à quiconque pouvant poster la réponse
    Va voir ce fil.
    Ça devrait te mettre sur la piste.

  14. #14
    Membre expérimenté
    Profil pro
    Inscrit en
    Février 2004
    Messages
    1 824
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2004
    Messages : 1 824
    Points : 1 544
    Points
    1 544
    Par défaut
    Impeccable, merci
    "Heureusement qu'il y avait mon nez, sinon je l'aurais pris en pleine gueule" Walter Spanghero

  15. #15
    Membre averti Avatar de vikki
    Profil pro
    Inscrit en
    Mai 2007
    Messages
    292
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations forums :
    Inscription : Mai 2007
    Messages : 292
    Points : 302
    Points
    302
    Par défaut
    Effectivement, en passant par les boost::function on supprime deja la macro DECLARE_CLASS, merci bien

  16. #16
    Membre expérimenté

    Profil pro
    Inscrit en
    Juin 2006
    Messages
    1 294
    Détails du profil
    Informations personnelles :
    Localisation : Royaume-Uni

    Informations forums :
    Inscription : Juin 2006
    Messages : 1 294
    Points : 1 543
    Points
    1 543
    Par défaut
    Salut,

    Citation Envoyé par vikki Voir le message
    J'avais l'habitude de voir les fabriques sous la forme d'une classe de base offrant la fonction virtuelle clone(), avec insertion d'un objet de chaque classe dans une map<string,ClassPrototype*>.
    Ca ressemble au design pattern prototype ça plutôt qu'à fabrique abstraite.

    MAT.

  17. #17
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Oui mais un type de fabrique utilise aussi le pattern prototype pour instancer...
    Voir ICI.

  18. #18
    Membre chevronné
    Avatar de poukill
    Profil pro
    Inscrit en
    Février 2006
    Messages
    2 155
    Détails du profil
    Informations personnelles :
    Âge : 40
    Localisation : France

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    Citation Envoyé par Laurent Gomila
    C'est très courant, et c'est même une meilleure solution car pour créer de nouveaux objets, on utilise une fonction plutôt qu'une instance bidon.

    Par contre l'intégration à base de macros n'est pas terrible, on peut faire ça beaucoup plus proprement.
    Laurent, pourrais-tu développer un peu?
    Concrêtement, comment s'affranchir des macros? C'est ce que j'utilise jusqu'à maintenant, alors si je peux faire mieux !

    Voici un aperçu du code que j'utilise : une factory dans un singleton, une classe descriptor qui est ma classe de base principale...
    Une définition de macro me sert à "register" mes fonctions de création.
    Le dernier exemple de code montre comment je l' implémente dans une classe concrète.

    Factory :
    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
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
    #ifndef OBJECT_FACTORY_H
    #define OBJECT_FACTORY_H
     
    #include <map>
    #include <boost/noncopyable.hpp>
    #include <boost/shared_ptr.hpp>
    #include <boost/function.hpp>
    #include <string>
     
    template <typename T>
    class object_factory : private boost::noncopyable
    {
    public:
     
    	static object_factory& instance()
    	{
    		static object_factory<T> instance;
    		return instance;
    	}
     
    	void register_object(const std::string& str, boost::function<boost::shared_ptr<T>(void)> func)
    	{
    		m_map[str] = func;
    	}
     
    	boost::shared_ptr<T> create(const std::string& str)
    	{
    		return m_map[str]();
    	}
     
    private:
    	object_factory() {}
    	std::map<std::string,  boost::function<boost::shared_ptr<T>(void)> > m_map;
    };
     
    #endif
    Classe de base: Descriptor
    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
    16
    17
    18
    19
    20
    21
    22
     
    #ifndef DESCRIPTOR_H
    #define DESCRIPTOR_H
     
    #define DECLARE_CLASS( __NAME__) \
    	static boost::shared_ptr<descriptor> create() \
    {\
    	return boost::shared_ptr<descriptor>(new __NAME__());  \
    }
     
    #define REGISTER_CLASS(__NAME__) \
    	object_factory<descriptor>::instance().register_object(#__NAME__, __NAME__::create);
     
    class descriptor
    {
    public:
    	descriptor() {}
    	virtual ~descriptor() {}
    };
     
     
    #endif
    Classe concrète :
    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
    16
    17
    18
    19
     
    #ifndef DESCRIPTOR_SHAPE_H
    #define DESCRIPTOR_SHAPE_H
     
    #include "Descriptor.h"
    #include "Point.h"
    #include <vector>
     
    class descriptor_shape : public descriptor
    {
    public:
    	DECLARE_CLASS(descriptor_shape)
    	descriptor_shape()
    	{
    		REGISTER_CLASS(descriptor_shape)
    	}
     
    	std::pair<Point<double>, Point<double>> m_Rect;
    };

Discussions similaires

  1. Fabriquer des requêtes sql à partir d'un document xml
    Par ktel dans le forum XQUERY/SGBD
    Réponses: 4
    Dernier message: 18/10/2005, 16h45
  2. Mon PC fait un drole de bruit que faire
    Par maceo dans le forum Composants
    Réponses: 6
    Dernier message: 09/05/2005, 22h02
  3. [GOF] Fabrique abstraite peut-elle être un Singleton ?
    Par manel007 dans le forum Design Patterns
    Réponses: 7
    Dernier message: 06/01/2005, 10h02
  4. [GOF] [Fabrique Abstraite] [Pont] Questions ?
    Par manel007 dans le forum Design Patterns
    Réponses: 5
    Dernier message: 04/01/2005, 20h18
  5. fabriquer un .X
    Par Fikus dans le forum DirectX
    Réponses: 4
    Dernier message: 23/03/2004, 15h24

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