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 :

[C++] Demande précision sur Pattern Factory


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut [C++] Demande précision sur Pattern Factory
    Bonsoir,

    Je n'arrive pas à comprendre l'intérêt du pattern Factory par rapport au polymorphisme.

    Voilà deux codes qui font la même chose :

    1ère version

    main.cpp
    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
    #include <iostream>
    #include "factory.h"
     
    using namespace std;
     
    int main()
    {
        Fabrique* factory = new Fabrique();
     
        if (factory)
        {
            Form* f1 = factory->create("cercle");
            Form* f2 = factory->create("carree");
            f1->Dessiner();
            f2->Dessiner();
     
            delete f1, f2, factory;
        }
     
        return 0;
    }
    factory.h
    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 FACTORY_H_INCLUDED
    #define FACTORY_H_INCLUDED
     
    #include "form.h"
     
    class Fabrique
    {
    public:
     
        Form* create(std::string quoi)
        {
            if (quoi == "cercle") return new Cercle();
            if (quoi == "carree") return new Carree();
            return NULL;
        }
    };
     
    #endif // FACTORY_H_INCLUDED
    form.h
    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 FORM_H_INCLUDED
    #define FORM_H_INCLUDED
     
    class Form
    {
        public:
            virtual void Dessiner() = 0;
    };
     
    class Cercle
        : public Form
    {
        public:
            Cercle(){};
            ~Cercle(){};
     
            inline virtual void Dessiner()
            {
                std::cout << "Je suis un cercle" << std::endl;
            }
    };
     
    class Carree
        : public Form
    {
        public:
            Carree(){};
            ~Carree(){};
     
            inline virtual void Dessiner()
            {
                std::cout << "Je suis un carree" << std::endl;
            }
    };
     
    #endif // FORM_H_INCLUDED
    2eme version :
    main.cpp
    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
     
    #include <iostream>
    #include "form.h"
     
    using namespace std;
     
    int main()
    {
        Form* f1 = new Cercle;
        f1->Dessiner();
     
        Form* f2 = new Carree;
        f2->Dessiner();
     
        delete f1, f2;
     
        return 0;
    }
    form.h
    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 FORM_H_INCLUDED
    #define FORM_H_INCLUDED
     
    class Form
    {
        public:
            virtual void Dessiner() = 0;
    };
     
    class Cercle
        : public Form
    {
        public:
            Cercle(){};
            ~Cercle(){};
     
            inline virtual void Dessiner()
            {
                std::cout << "Je suis un cercle" << std::endl;
            }
    };
     
    class Carree
        : public Form
    {
        public:
            Carree(){};
            ~Carree(){};
     
            inline virtual void Dessiner()
            {
                std::cout << "Je suis un carree" << std::endl;
            }
    };
     
    #endif // FORM_H_INCLUDED
    Pour moi, la 2eme version est plus facile d'utilisation pour un résultat identique.

    A mon avis, j'ai mal compris l'idée du pattern Factory :
    http://come-david.developpez.com/tut...e=Fabrique#LIV

    Pourtant, je pense l'avoir bien implémenté...

    Pouvez vous m'éclairez d'avantage ?

    Merci à tous
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  2. #2
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Imagine la situation suivante, à l'execution le programme demande à l'utilisateur ce qu'il veut créer sous la forme d'un identifiant (une chaine de caractère, ou autre, peu importe) parmi un ensemble de possibilité. La factory te permet de faire ca. Tu l'as mal implémenter, normalement il y a une fonction qui permet d'enregistrer les divers élément que tu veux créer. Relis le code de David Come, ou l'implémentation de ce pattern dans certaines bibliothèque : Poco, Loki.

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Le pattern factory a, justement, pour but de te permettre d'utiliser le polymorphisme sans avoir à t'inquiéter du type réel de l'objet créé, et donc, en minimisant les dépendances entre l'endroit où l'objet polymorphe est utilisé et le type réel de celui-ci.

    Dans le cas que tu présentes, l'idée est de permettre à l'utilisateur de connaitre l'existence de la fabrique d'une part et du type "Forme" d'autre part, sans s'inquiéter du fait que Forme est dérivé en plusieurs types particuliers.

    Après tout: tant que tu te contente d'invoquer des comportements polymorphes tels que dessiner sur tes objets, tu n'as strictement pas besoin de savoir qu'il existe différents type de Forme


    Cela te permet, non seulement, d'adopter un desing beaucoup plus simple, mais aussi, d'augmenter le respect du principe nommé OCP (Open Close Principle)
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Citation Envoyé par Flob90 Voir le message
    Imagine la situation suivante, à l'execution le programme demande à l'utilisateur ce qu'il veut créer sous la forme d'un identifiant (une chaine de caractère, ou autre, peu importe) parmi un ensemble de possibilité. La factory te permet de faire ca. Tu l'as mal implémenter, normalement il y a une fonction qui permet d'enregistrer les divers élément que tu veux créer. Relis le code de David Come, ou l'implémentation de ce pattern dans certaines bibliothèque : Poco, Loki.
    Dans un design Factory, il y a toujours une fonction Register ? Car j'ai (cru) voir des codes sans cette fonction et je n'en vois pas trop son utilité

    Donc si je comprends bien, avec ce pattern, je peux demander à l'utilisateur de dessiner un cercle (en récupérant sa saisie dans un cin par exemple) ou une autre forme parmi celle que j'ai programmées ? Alors qu'avec du polymorphisme classique, c'est impossible... AI-je bien compris ?

    Citation Envoyé par koala01
    Dans le cas que tu présentes, l'idée est de permettre à l'utilisateur de connaitre l'existence de la fabrique d'une part et du type "Forme" d'autre part, sans s'inquiéter du fait que Forme est dérivé en plusieurs types particuliers.

    Après tout: tant que tu te contente d'invoquer des comportements polymorphes tels que dessiner sur tes objets, tu n'as strictement pas besoin de savoir qu'il existe différents type de Forme
    Je n'arrive pas à saisir ce que vous voulez dire et surtout l'intérêt de ce pattern. Peut être que mon exemple est nul donc si vous aviez un autre exemple plus parlant sur le réel intérêt de ce pattern par rapport au polymorphisme classique, je suis preneur
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  5. #5
    Membre Expert

    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Août 2004
    Messages
    1 391
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 391
    Par défaut
    Il n'y a pas de choix à faire entre ce pattern et le polymorphisme. Bien au contraire si tu utilises le pattern factory, tu utilises aussi le polymorphisme


    Le polymorphisme est un mécanisme qui permet d'avoir des comportements différent selon le type réel de l'objet et non le type statique (celui que "voit" le compilateur).

    La factory te permet de choisir que type d'objet créer de manière dynamique (ie à l'execution).


    Là où tu utilises le polymorphisme c'est que ta fonction de création de ta factory va te retourner via pointeur (ou référence) sur un type de base des objets de types filles : le type réel est celui du type fille que tu veux, le type statique est celui du type de base, dès que tu vas utiliser ces objets le polymorphisme entre en jeu, les bonnes fonction sont appelé.

    Pour la fonction register, la manière classique de faire est avec celle-ci (il faut que tu enregistres préallablement les différents objets (*) que tu veux pouvoir instancier ensuite). Pour des besoins précis on peut peut-être s'en passer, mais c'est du cas par cas


    Regardes ceci : http://pocoproject.org/slides/030-MemoryManagement.pdf (pages 31 à 38), c'est la factory proposé par Poco (*). Tu peux aussi regarder le code (il y a des élément multi-thread dedans, oublie les dans un premier temps). Je trouve l'interface assez simple et clair (Loki est plus complexe)



    (*) Pour être plus précis ce peut être des objets d'un type différent qui permet de créer des objets des types voulus.

  6. #6
    Rédacteur/Modérateur
    Avatar de JolyLoic
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    5 463
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 50
    Localisation : France, Yvelines (Île de France)

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

    Informations forums :
    Inscription : Août 2004
    Messages : 5 463
    Par défaut
    Le polymorphisme, c'est avant tout manipuler divers objets sans connaître leur type exact. Or il y a un moment où la connaissance du type exact est nécessaire : La création de l'objet.

    Le but du pattern factory est d'encapsuler la connaissance du type exact à la création, de manière à avoir un choix flexible de ce type.

    A titre d'exo, je t'invite à écrire du code pour sauver dans un fichier, puis surtout recharger de ce fichier, un vector<Form*>. L'intérêt de la factory devrait t'apparaître.

    La notion de register est très importante, mais j'avoue que je m'en passe assez souvent quand je dois code rapidement un prototype. Un des concepts de l'orienté objet est l'open-closed principle : On peut modifier le comportement d'un code en ajoutant du code, mais sans modifier le code existant. C'est à ça que sert register : Tu peux ajouter une nouvelle classe à celles gérées par la factory, sans changer une ligne de code dans le code existant, simplement en enregistrant ta nouvelle classe.
    Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
    Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
    Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
    Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.

  7. #7
    Membre Expert
    Avatar de Aspic
    Homme Profil pro
    Étudiant
    Inscrit en
    Août 2005
    Messages
    3 905
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Août 2005
    Messages : 3 905
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Le polymorphisme, c'est avant tout manipuler divers objets sans connaître leur type exact. Or il y a un moment où la connaissance du type exact est nécessaire : La création de l'objet.

    Le but du pattern factory est d'encapsuler la connaissance du type exact à la création, de manière à avoir un choix flexible de ce type.

    A titre d'exo, je t'invite à écrire du code pour sauver dans un fichier, puis surtout recharger de ce fichier, un vector<Form*>. L'intérêt de la factory devrait t'apparaître.

    La notion de register est très importante, mais j'avoue que je m'en passe assez souvent quand je dois code rapidement un prototype. Un des concepts de l'orienté objet est l'open-closed principle : On peut modifier le comportement d'un code en ajoutant du code, mais sans modifier le code existant. C'est à ça que sert register : Tu peux ajouter une nouvelle classe à celles gérées par la factory, sans changer une ligne de code dans le code existant, simplement en enregistrant ta nouvelle classe.
    Je crois que je commence à comprendre l'utilité de ce pattern. Avec ton exemple, sans la factory, il est impossible de charger des classes à partir d'un fichier texte

    Par contre, je suis entrain d'implémenter la version avec un register mais j'ai un problème car je ne veux pas créer les objets en les clonant mais en utilisant "new" :
    Citation Envoyé par tutoriel de come-david
    Avant toute chose, il faut préciser comment seront créés les objets. En effet, sur ce point, plusieurs stratégies sont envisageables telle la création via new ou celle par clonage. Pour ma part, j'ai choisi celle basée sur le clonage. Mais vous trouverez facilement d'autres implémentations sur le web.
    Je vous donne mon code :
    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
    class Fabrique
    {
    public:
     
        std::map<std::string, Form*> m_map;
     
        //Fonction qui associe clé <=> prototype
        void Register(const std::string& key, Form* obj)
        {
            //si la clé n'est pas déjà présente
            if(m_map.find(key)==m_map.end())
            {
                //on ajoute l'objet dans la map
                m_map[key] = obj;
            }
        }
     
     
        Form* create(const std::string& key)
        {
            Form* tmp = NULL;
            std::map<std::string, Form*>::const_iterator it = m_map.find(key);
     
            //si l'itérateur ne vaut pas map.end(), cela signifie que que la clé à été trouvée
            if(it != m_map.end())
            {
                //tmp = (*it).second->Clone();
                // ici comment dire si je veux un carree alors faire new Caree(); ...
            }
     
            return tmp;
        }
    };
    Dans tous les codes sur le net, ils utilisent des if pour faire un truc du genre :
    // Si key == "carree" alors return new Carree();
    // si key == "cercle" alors return new Cercle();
    Sauf que si j'ai bien compris et que je veux respecter l'open-closed en POO, je ne dois pas modifier le code de la classe si je décide d'enregistrer une nouvelle classe.
    Or avec la technique des "if" je dois modifier le code à chaque ajout... D'où l'utilisation d'une map je suppose mais encore une fois, je ne vois pas comment faire

    EDIT :
    J'ai vu que la fonction Register était statique. Est-ce obligatoire ? qu'est ce que ca change concrètement ?
    Qui ne tente rien n'a rien !
    Ce qui ne nous tue pas nous rends plus fort !!
    Mon projet ZELDA en C++/Allegro
    http://www.tutoworld.com - Le Forum -
    Mes ressources Dotnet (cours, sources, tutos)
    --------------------------------------------
    + + =

    Ne pas oublier le Tag !

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Aspic Voir le message
    Form* f1 = factory->create("cercle");
    Form* f2 = factory->create("carree");
    Imagine maintenant que tu as un programme en ligne de commande, et que c'est en cours d'exécution que l'utilisateur demande au programme de créer un cercle ou un carré.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 16
    Dernier message: 26/08/2011, 22h02
  2. [MySQL] Demande précisions sur LOCK TABLE
    Par renaud26 dans le forum PHP & Base de données
    Réponses: 8
    Dernier message: 15/04/2011, 13h49
  3. Demande de précision sur "Extends" ..
    Par Invité dans le forum Langage
    Réponses: 6
    Dernier message: 12/02/2006, 14h25
  4. Demande de précisions sur Backup/Restore et transactions
    Par lio33 dans le forum Connexion aux bases de données
    Réponses: 1
    Dernier message: 16/11/2005, 12h08
  5. [Observateur] Précisions sur le design pattern Observer [UML]
    Par joquetino dans le forum Design Patterns
    Réponses: 2
    Dernier message: 07/10/2004, 22h35

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