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++/CLI Discussion :

Design pattern : factory


Sujet :

C++/CLI

  1. #1
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Analyse système

    Informations forums :
    Inscription : Novembre 2014
    Messages : 14
    Par défaut Design pattern : factory
    Bonjour,
    J'essaye d'implémenter pour la première fois le design pattern factory en C++.
    J'ai donc une classe Object défini comme suit :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    class Object {
     
    public:
    	virtual Object* clone() = 0;
    };
    Et une classe Tile qui en hérite :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class Tile : public Object {
    public:
    	Tile();
            getId();
    	Object* clone();
    };
    (Pour l'instant je n'ai que celle là mais à l'avenir d'autres viendrons s'ajouter)

    Enfin voici ma classe objectfactory qui est d'ailleurs un singleton :
    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
    class ObjectFactory : Singleton<ObjectFactory> {
    friend class Singleton<ObjectFactory>;
     
    private:
    	ObjectFactory();
    	~ObjectFactory();
     
    public:
    	void add(std::string const& key, Object* obj) {
    		_mapFactory[key] = obj;
    	}
    	Object* construct(std::string const& key) {
    		Object* tmp = 0;
    		tmp = _mapFactory.at(key)->clone();
    		return tmp;	
    	}
    private:
    	std::map<std::string, Object*> _mapFactory;
    };
    Le problème viens que je peut écrire ce code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    ObjectFactory* obj = Singleton<ObjectFactory>::instance();
    obj->add("Tile", new Tile);
    Object* t = obj->construct("Tile");
    Mais après je ne peux rien faire faire avec mon objet t. Je ne peux pas accèder aux méthodes de Tile. Je ne peux par exemple par écrire :
    Comment résoudre ce problème ? Merci de votre aide !

  2. #2
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 512
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 512
    Par défaut
    Bonjour,

    L'intérêt du patron de conception Factory method, c'est de pouvoir ne pas connaître à la compilation le type réel de l'objet construit.

    Ta méthode Object* construct(std::string const& key) permet de construire un objet dont le type réel est inconnu à la compilation, mis à part le fait que ce type doit dériver de Object. Mais, en contrepartie, effectivement, tu ne peux pas appeler des méthodes absentes de la classe Object.

    Si tu as besoin en plus de construire un objet pour lequel le compilateur doit savoir que le type dérive de Tile, il faut ajouter une fonction Tile* constructTile(std::string const& key) const ou, encore mieux, std::unique_ptr<Tile> constructTile(std::string const& key) const.

    Voici le code correspondant (j'ai tout recodé) :
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    #include <iostream>
    #include <map>
    #include <memory>
    #include <string>
     
    template<class T>
    class SingletonCRTP
    {
        SingletonCRTP(SingletonCRTP const& other)            = delete;
        SingletonCRTP& operator=(SingletonCRTP const& other) = delete;
    public:
        static T& instance() {return _instance;}
    protected:
        SingletonCRTP() {}
    private:
        static T _instance;
    };
     
    template<class T>
    T SingletonCRTP<T>::_instance;
     
    class Object
    { 
    public:
        virtual ~Object() {}
        inline std::unique_ptr<Object> clone() const
        {
            return std::unique_ptr<Object>(virtClone());
        }
    private:
        virtual Object* virtClone() const = 0;
    };
     
    class Tile : public Object
    {
    public:
        explicit Tile(int id) : _id(id) {}
        ~Tile() override {}
        inline std::unique_ptr<Tile> clone() const
        {
            return std::unique_ptr<Tile>(virtClone());
        }
        inline int getId() const {return _id;}
    private:
        Tile* virtClone() const override
        {
            return new Tile(*this);
        }
        int _id;
    };
     
    class ObjectFactory : public SingletonCRTP<ObjectFactory>
    {
        friend class SingletonCRTP<ObjectFactory>;
    private:
        ObjectFactory()  {}
        ~ObjectFactory() {}
    public:
        void addObject(std::string const& key, Object const& obj)
        {
            _mapFactoryObject[key] = &obj;
        }
        void addTile(std::string const& key, Tile const& tile)
        {
            _mapFactoryObject[key] = &tile;
            _mapFactoryTile  [key] = &tile;
        }
        std::unique_ptr<Object> constructObject(std::string const& key) const
        {
            Object const* tmp = _mapFactoryObject.at(key);
            return tmp->clone();    
        }
        std::unique_ptr<Tile> constructTile(std::string const& key) const
        {
            Tile const* tmp = _mapFactoryTile.at(key);
            return tmp->clone();    
        }
    private:
        std::map<std::string, Object const*> _mapFactoryObject;
        std::map<std::string, Tile   const*> _mapFactoryTile;
    };
     
    int main()
    {
        ObjectFactory& objectFactory = ObjectFactory::instance();
        Tile tile1(1);
        Tile tile2(2);
        objectFactory.addTile("Tile 1", tile1);
        objectFactory.addTile("Tile 2", tile2);
        std::unique_ptr<Tile> toto = objectFactory.constructTile("Tile 1");
        std::cout << "Id de toto : " << toto->getId() << "\n";
        return 0;
    }
    Remarques sur le code :
    • Ne pas oublier const pour les méthodes qui ne modifient pas l'objet.
    • Quand c'est possible, préférer une référence à un pointeur si ledit pointeur doit être non nul. => FAQ C++
    • Préférer std::unique_ptr à un pointeur nu si ledit pointeur est responsable de libérer la ressource. => FAQ C++
    • Dans une classe A, quand une fonction virtuelle foo retourne un pointeur ou une référence vers une classe X alors, dans une classe B qui dérive de A, on peut modifier le type de retour de B::foo en un pointeur ou une référence vers une classe Y qui dérive de X. C'est le principe des types de retour covariants.
      Cela permet à l'utilisateur d'éviter de faire sauvagement du downcasting de X vers Y.
      Dans mon code, j'ai utilisé ce principe avec foo = virtClone() const, A = X = Object et B = Y = Tile.

  3. #3
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Analyse système

    Informations forums :
    Inscription : Novembre 2014
    Messages : 14
    Par défaut
    Merci de ta réponse.
    Maintenant si j'ai plusieurs cas comme Tile ? Imaginons que j'ai plusieurs objets qui doivent être créer de la même façon...
    Au début j’étais partit sur une idée de if..elseif ou je créer l'objet en fonction mais ça demander de rajouter du code à chaque fois...

  4. #4
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 512
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 512
    Par défaut
    Citation Envoyé par loustak Voir le message
    Maintenant si j'ai plusieurs cas comme Tile ?
    Je viens de modifier le code :
    • J'ai créé un modèle de classe ObjectFactory<T>.
    • Quand on ajoute un Tile dans ObjectFactory<Tile>, ça l'ajoute aussi dans ObjectFactory<Object>.
    • J'ai ajouté une classe TileDeriv qui dérive de Tile. Quand on ajoute un TileDeriv dans ObjectFactory<TileDeriv>, ça l'ajoute aussi dans ObjectFactory<Tile> et dans ObjectFactory<Object>.


    Voici le code modifié :
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    #include <iostream>
    #include <map>
    #include <memory>
    #include <string>
     
    template<class T>
    class SingletonCRTP
    {
        SingletonCRTP(SingletonCRTP const& other)            = delete;
        SingletonCRTP& operator=(SingletonCRTP const& other) = delete;
    public:
        static T& instance() {return _instance;}
    protected:
        SingletonCRTP() {}
    private:
        static T _instance;
    };
     
    template<class T>
    T SingletonCRTP<T>::_instance;
     
    class Object
    { 
    public:
        virtual ~Object() {}
        inline std::unique_ptr<Object> clone() const
        {
            return std::unique_ptr<Object>(virtClone());
        }
    private:
        virtual Object* virtClone() const = 0;
    };
     
    class Tile : public Object
    {
    public:
        typedef Object typeParent; // lu par le code de ObjectFactory
        explicit Tile(int id) : _id(id) {}
        ~Tile() override {}
        inline std::unique_ptr<Tile> clone() const
        {
            return std::unique_ptr<Tile>(virtClone());
        }
        inline int getId() const {return _id;}
    private:
        Tile* virtClone() const override
        {
            return new Tile(*this);
        }
        int _id;
    };
     
    class TileDeriv : public Tile
    {
    public:
        typedef Tile typeParent; // lu par le code de ObjectFactory
        TileDeriv(int id, int idBis) : Tile(id), _idBis(idBis) {}
        ~TileDeriv() override {}
        inline std::unique_ptr<TileDeriv> clone() const
        {
            return std::unique_ptr<TileDeriv>(virtClone());
        }
        inline int getIdBis() const {return _idBis;}
    private:
        TileDeriv* virtClone() const override
        {
            return new TileDeriv(*this);
        }
        int _idBis;
    };
     
    template<class T>
    class ObjectFactory;
     
    template<>
    class ObjectFactory<Object> : public SingletonCRTP<ObjectFactory<Object>>
    {
        friend class SingletonCRTP<ObjectFactory<Object>>;
    private:
        ObjectFactory<Object>()  {}
        ~ObjectFactory<Object>() {}
    public:
        void add(std::string const& key, Object const& obj)
        {
            _mapFactory[key] = &obj;
        }
        std::unique_ptr<Object> construct(std::string const& key) const
        {
            Object const* tmp = _mapFactory.at(key);
            return tmp->clone();    
        }
    private:
        std::map<std::string, Object const*> _mapFactory;
    };
     
    template<class T>
    class ObjectFactory : public SingletonCRTP<ObjectFactory<T>>
    {
        friend class SingletonCRTP<ObjectFactory<T>>;
    private:
        ObjectFactory() : _objectFactoryParent(ObjectFactory<typename T::typeParent>::instance()) {}
        ~ObjectFactory() {}
    public:
        void add(std::string const& key, T const& specificObject)
        {
            _objectFactoryParent.add(key, specificObject);
            _mapFactory[key] = &specificObject;
        }
        std::unique_ptr<T> construct(std::string const& key) const
        {
            T const* tmp = _mapFactory.at(key);
            return tmp->clone();    
        }
    private:
        ObjectFactory<typename T::typeParent>& _objectFactoryParent;
        std::map<std::string, T const*>        _mapFactory;
    };
     
    int main()
    {
        ObjectFactory<Tile>&      tileFactory      = ObjectFactory<Tile>::instance();
        ObjectFactory<TileDeriv>& tileDerivFactory = ObjectFactory<TileDeriv>::instance();
        Tile      tile(1);
        TileDeriv tileDeriv(2, 3);
        tileFactory     .add("Tile 1",        tile);
        tileDerivFactory.add("TileDeriv 2-3", tileDeriv);
        std::unique_ptr<Tile>      toto = tileFactory     .construct("TileDeriv 2-3");
        std::unique_ptr<TileDeriv> titi = tileDerivFactory.construct("TileDeriv 2-3");
        std::cout << "Id de toto    : " << toto->getId()    << "\n";
        std::cout << "IdBis de titi : " << titi->getIdBis() << "\n";
        return 0;
    }

  5. #5
    Membre averti
    Homme Profil pro
    Analyse système
    Inscrit en
    Novembre 2014
    Messages
    14
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Analyse système

    Informations forums :
    Inscription : Novembre 2014
    Messages : 14
    Par défaut
    Ok merci j'ai réussi !

Discussions similaires

  1. design pattern factory
    Par olive_le_malin dans le forum C++
    Réponses: 2
    Dernier message: 23/08/2007, 15h31
  2. Classe + design pattern factory
    Par Rodrigue dans le forum C++
    Réponses: 8
    Dernier message: 07/11/2006, 14h42
  3. [Conception]Design Pattern Factory ?
    Par ®om dans le forum Logging
    Réponses: 8
    Dernier message: 13/09/2006, 10h20
  4. [Fabrique] [Java] Design Pattern Factory
    Par SkyBioSS dans le forum Design Patterns
    Réponses: 3
    Dernier message: 24/05/2006, 14h53

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