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 :

Quelques questions sur les design pattern


Sujet :

C++

  1. #1
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut Quelques questions sur les design pattern
    Bonjour,

    Mes questions concernent les design montrés sur cette page.

    Tout d'abord, commençons par le design pattern "Prototype" qui décrit le clonage.

    Tout d'abord, n'est-il pas dangereux ici d'effectuer un new dans la classe et d'effectuer le delete en dehors de la classe ?

    Tel que:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    MySQLManager* MySQLManager::Clone() const 
    {
           //le constructeur de recopie fait tout le travail à notre place.
    	return (new MySQLManager(*this));
    }
    et

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MySQLManager* manager2=manager1->Clone();
    delete manager2;
    Personnellement, je trouve que cette méthode pas très propre, à savoir que selon moi, c'est l'instance qui a alloué la mémoire qui doit la libérer.

    Aussi, pourquoi s'ennuyer à créer une méthode "clone" alors que le constructeur de copie par défaut ferait très bien le boulot ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    MySQLManager manager2 = manager1;
    est-il moins propre ?

    Ensuite, toujours dans ce même design, l'utilisation des templates est-elle justifiée dans le but de généricité ? Personellement, je ne vois ce qu'apporte les templates de plus dans ce cas précis.

    Ensuite, pour le design Singleton, je vais mettre un code et une citation pour que ça soit plus clair (du lien fournis plus haut):

    En effet, avec la classe singleton actuelle, il faut faire hériter de Singleton la classe que l'on souhaite avoir en unique exemplaire. Or la classe Singleton est template, le seul moyen de l'instancier est donc de passer la classe dérivée en paramètre de Singleton.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    int main(void)
    {
    	SoundManager* sin=Singleton<SoundManager>::Get();
    	SoundManager* sin2=Singleton<SoundManager>::Get();
    	std::cout<<sin<<"|"<<sin2<<std::endl;
    	Singleton<SoundManager>::Kill();
    }
    Je ne comprends rien mais strictement rien.
    En quoi cette écriture serait moins adaptée ? :

    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
     
    #include <iostream>
     
    template< class T >
    class Singleton
    {
    protected:
        static T* m_instance;
     
    public:
        static T * const & Get()
        {
            if( !m_instance )
            {
                m_instance = new T();
            }
            return m_instance;
        }
     
        static void Kill()
        {
            delete m_instance;
            m_instance = 0;
        }
    };
     
    template <class T>
    T* Singleton<T>::m_instance=0;
     
    class SoundManager : public Singleton<SoundManager>
    {
        //...
        std::string m_str;
     
        friend SoundManager * const& Singleton<SoundManager>::Get();
        friend void Singleton<SoundManager>::Kill();
     
        SoundManager() :
            m_str("Quelque chose")
        {
            std::cout << "Creation" << std::endl;
        }
     
        ~SoundManager()
        {
            std::cout << "Destruction" << std::endl;
        }
     
    public:
        void Do()
        {
            std::cout << m_str << std::endl;
        }
    };
     
    int main()
    {
        typedef SoundManager * const & SoundManagerRefPtr;
        SoundManagerRefPtr sin1 = SoundManager::Get();
        sin1->Do();
        SoundManagerRefPtr sin2 = SoundManager::Get(); // Pour montrer qu'il n'y a pas double création
        std::cout << sin1 << " | " << sin2 << std::endl;
        SoundManager::Kill();
        std::cout << sin1 << " | " << sin2 << std::endl;
        SoundManager::Kill(); // Pour montrer qu'il n'y a pas double destruction
     
        return 0;
    }
    J'ai d'autres questions en attente mais j'aimerais déjà avoir réponse à ceux-ci car je crois avoir zappé quelques trucs et donc ai un peu peur de l'idiotie de mes autres questions...

  2. #2
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Mes questions concernent les design montrés sur cette page.
    Cet article ne me semble pas forcément terrible. Il faut toujours avoir un regard critique sur ce qu'on lit. Y'a sûrement du bon dedans, mais aussi du moins bon.

    Aussi, pourquoi s'ennuyer à créer une méthode "clone" alors que le constructeur de copie par défaut ferait très bien le boulot ?
    La copie-construction ne peut fonctionner que si tu connais le type réel de l'objet à copier.
    La fonction clone peut quant à elle être virtuelle, c'est là tout l'intérêt du truc. Tu peux ainsi copier un objet sans connaître son type réel.

    Personnellement, je trouve que cette méthode pas très propre, à savoir que selon moi, c'est l'instance qui a alloué la mémoire qui doit la libérer.
    Et tu as parfaitement raison. Le principe selon lequel toute ressource, comme la mémoire, est allouée par un objet dans son constructeur et libérée par le même objet dans son destructeur s'appelle le RAII.

    La solution appréciée ici est typiquement d'utiliser std::auto_ptr, qui sera remplacé dans la prochaine version de C++ par std::unique_ptr. (personnellement, je ferais plutôt autrement pour éviter d'exposer des pointeurs, même intelligents, mais c'est juste mon opinion personnelle)

    Ensuite, toujours dans ce même design, l'utilisation des templates est-elle justifiée dans le but de généricité ? Personellement, je ne vois ce qu'apporte les templates de plus dans ce cas précis.
    C'est pas hyper utile, non, autant tout faire directement dans MySQLManager.

    J'ai pas vraiment compris pourquoi y'avait des templates dans les autres trucs aussi, comme le singleton, ni même pourquoi y'avait des fonctions membres amies.
    Il devait essayer de faire un genre de mixin, mais c'est super mal fait...

    Surtout que les singletons, c'est un domaine archi-connu, et que y'a de bien meilleures façons d'en faire (dont certaines sont rendues thread-safe et efficaces par le compilo lui-même).

  3. #3
    Membre confirmé
    Inscrit en
    Août 2004
    Messages
    556
    Détails du profil
    Informations forums :
    Inscription : Août 2004
    Messages : 556
    Points : 588
    Points
    588
    Par défaut
    Citation Envoyé par loufoque Voir le message
    La copie-construction ne peut fonctionner que si tu connais le type réel de l'objet à copier.
    La fonction clone peut quant à elle être virtuelle, c'est là tout l'intérêt du truc. Tu peux ainsi copier un objet sans connaître son type réel.
    Ok, l'article n'ayant pas avancé la nécessite de pouvoir cloner la hiérarchie montante d'un objet, je n'ai pas pensé à cette éventualité et me suis fixer sur ce cas précis, où l'utilisation du clonage me semble tout de même assez inutile. Peut-être l'exemple a-t-il été mal choisi.

    La solution appréciée ici est typiquement d'utiliser std::auto_ptr, qui sera remplacé dans la prochaine version de C++ par std::unique_ptr. (personnellement, je ferais plutôt autrement pour éviter d'exposer des pointeurs, même intelligents, mais c'est juste mon opinion personnelle)
    J'use et j'abuse déjà depuis un moment du boost::shared_ptr et j'attend que les pointeurs intelligents de la TR1 aient les même possibilités avant de l'utiliser

    Je continue donc dans ma lancée:

    Concernant le pattern Fabrique, même chose que le design Prototype, il serait mieux d'envisager que la classe Fabrique supprime d'elle même les ressources qu'elle a allouée. Surtout que je vois très mal, dans son exemple, comment il compte gérer son std::map dans sa Fabrique lorsqu'un objet est détruit en externe, ou pire, qu'un nouvel objet ayant la même clé ait été créer, ce qui rendra la désallocation de l'ancien objet impossible tout simplement. Bref, une manière de coder le pattern Factory que je désapprouve. Ai-je tort ou y a-t-il une subtilité que j'ai zappé ?

    Je ne me considère vraiment pas comme un programmeur très averti/experimenté, je demande donc s'il y aurait des subtilités dans ces pattern qui m'échappent (étant donné que l'article en question est la 1ère réponse qui arrive quand on cherche "design pattern C++" sur google :p)

  4. #4
    Expert confirmé
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Décembre 2003
    Messages
    3 549
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

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

    Informations forums :
    Inscription : Décembre 2003
    Messages : 3 549
    Points : 4 625
    Points
    4 625
    Par défaut
    Les design patterns ça marche mieux dans un langage garbage collecté à la Java, où on ne se soucie pas de la gestion mémoire.
    Apparemment, cet article ne se soucie pas de la gestion mémoire non plus.

  5. #5
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Salut,

    Le fait est que, bien souvent, les DP s'inter-connectent énormément...

    Un DP Prototype ne trouvera toute son utilité que... dans le cadre de l'utilisation d'une fabrique, par exemple.

    La fabrique ne trouvera réellement son utilité que... couplée avec une facade, un adatpateur, ou un gestionnaire de ressource quelconque...

    Et le gestionnaire de ressource quelconque prendra régulièrement la forme ... d'un singleton...

    (ce ne sont que des exemples, et absolument pas des obligations )

    Tout cela permet d'éviter énormément de dépendances "indues" (ou considérables comme telles)...

    Ainsi, un gestionnaire de connexions SQL (par exemple) ne devra absolument pas connaitre toutes les classes de connexion existantes:

    Pour appeler le constructeur des différentes connexions, il devrait disposer de la définition de chacune d'elles, et cela peut faire beaucoup...

    Par contre, la fabrique et le polymorphisme aidant, tout ce qu'il a besoin de connaitre, c'est la définition de la fabrique et celle... de l'interface des connexions...

    Si tu as cinq connexions à des BDD différentes, comme
    • la connexion à une base MsSql
    • la connexion à une base MySql
    • la connexion à une base Oracle
    • la connexion à une base Excell
    • la connexion à une base PosGres
    tu te retrouve, dans un cas, avec cinq dépendances et, dans l'autre cas, avec deux seulement (la fabrique et l'interface "SqlConnecion")

    Par contre, il est vrai que l'auteur n'a pas penser à utiliser CRTP en ce qui concerne le singleton templatisé

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

    Informations forums :
    Inscription : Février 2006
    Messages : 2 155
    Points : 2 107
    Points
    2 107
    Par défaut
    C'est sûr que l'exemple de l'article n'est peut-être pas idéal.
    Laurent Gomila m'avait aidé à écrire une fabrique correspondant à mes besoins, sans prototype, ni CRTP. Comme quoi les DP sont pas forcément couplés ! (bon y'a du boost::function, mais bon...)
    C'est simple, mais ça marche à peu près pour tout.
    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
     
    #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, typename U>
    boost::shared_ptr<T> create()
    {
        return boost::shared_ptr<T>(new U());
    }
     
    template <typename T>
    class object_factory : private boost::noncopyable
    {
    public:
    	static object_factory& instance()
    	{
    		static object_factory<T> instance;
    		return instance;
    	}
     
    	void register_class(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;
    };
     
     
    template <typename T, typename U>
    void register_class(const std::string& name)
    {
        object_factory<T>::instance().register_class(name, &create<T, U>);
    }
     
     
    #endif

  7. #7
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 632
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 632
    Points : 30 711
    Points
    30 711
    Par défaut
    Citation Envoyé par poukill Voir le message
    C'est sûr que l'exemple de l'article n'est peut-être pas idéal.
    Laurent Gomila m'avait aidé à écrire une fabrique correspondant à mes besoins, sans prototype, ni CRTP. Comme quoi les DP sont pas forcément couplés ! (bon y'a du boost::function, mais bon...)
    C'est simple, mais ça marche à peu près pour tout.
    C'est bien pour cela que j'ai précisé que ce ne sont que des exemples, et que ce n'est absolument pas des obligations

    On remarque souvent les couplages dont j'ai parlé, mais il y a parfaitement moyen de "faire sans" (bien que l'on puisse effectivement se poser la question de l'utilité de certains DP si c'est pour les utiliser seuls )

  8. #8
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Salut à tous, désolé pour le temps de réponse, j'étais pas mal occupé dans mes révisions :p.

    Je vais essayer de me justifier et faire des modifications en tenant compte de vos remarques.

    Tout d'abord, commençons par le design pattern "Prototype" qui décrit le clonage.

    Tout d'abord, n'est-il pas dangereux ici d'effectuer un new dans la classe et d'effectuer le delete en dehors de la classe ?

    Personnellement, je trouve que cette méthode pas très propre, à savoir que selon moi, c'est l'instance qui a alloué la mémoire qui doit la libérer.

    Aussi, pourquoi s'ennuyer à créer une méthode "clone" alors que le constructeur de copie par défaut ferait très bien le boulot ?
    OUi et tu as raison. Quand j'ai écrit l'article, je ne voulais pas dépendre de boost et les pointeurs inteligents de la STL sont naze. je vais sans doute revoir ma position et aussi ajouter (je ne sais pas pourquoi je ne l'ai pas fais), le fait de pouvoir copier une hiérarchie polymorphe.

    Ensuite, toujours dans ce même design, l'utilisation des templates est-elle justifiée dans le but de généricité ? Personellement, je ne vois ce qu'apporte les templates de plus dans ce cas précis.
    Eviter de se manger une super classe de base comme en Java.


    Ensuite, pour le design Singleton, je vais mettre un code et une citation pour que ça soit plus clair (du lien fournis plus haut):

    Je ne comprends rien mais strictement rien.
    En quoi cette écriture serait moins adaptée ? :
    Renvoyer pointeur ou référence, un choix que j'avais fait en faveur des pointeurs. Position à revoir aussi (moins il y a de pointeurs, mieux on se porte).
    Citation Envoyé par loufoque Voir le message
    Cet article ne me semble pas forcément terrible. Il faut toujours avoir un regard critique sur ce qu'on lit. Y'a sûrement du bon dedans, mais aussi du moins bon.
    je sais et j'ai déjà envisagé de le refondre de A-Z.

    Il devait essayer de faire un genre de mixin, mais c'est super mal fait...
    Luc m'avait parlé des mixin.

    Je n'aavais pas approfondi la chose surtout à cause de mon niveau d'anglais de l'époque. C'est un tord, je sais.
    Au passage, une doc sur les mixin layer
    Surtout que les singletons, c'est un domaine archi-connu, et que y'a de bien meilleures façons d'en faire (dont certaines sont rendues thread-safe et efficaces par le compilo lui-même).
    Là, je veux bien quelques détails, tu m'intéresse beaucoup
    Citation Envoyé par loufoque Voir le message
    Les design patterns ça marche mieux dans un langage garbage collecté à la Java, où on ne se soucie pas de la gestion mémoire.
    Apparemment, cet article ne se soucie pas de la gestion mémoire non plus.
    J'essaye autant que je peux

    Citation Envoyé par JulienDuSud Voir le message

    Je continue donc dans ma lancée:

    Concernant le pattern Fabrique, même chose que le design Prototype, il serait mieux d'envisager que la classe Fabrique supprime d'elle même les ressources qu'elle a allouée. Surtout que je vois très mal, dans son exemple, comment il compte gérer son std::map dans sa Fabrique lorsqu'un objet est détruit en externe, ou pire, qu'un nouvel objet ayant la même clé ait été créer, ce qui rendra la désallocation de l'ancien objet impossible tout simplement. Bref, une manière de coder le pattern Factory que je désapprouve. Ai-je tort ou y a-t-il une subtilité que j'ai zappé ?

    Je ne me considère vraiment pas comme un programmeur très averti/experimenté, je demande donc s'il y aurait des subtilités dans ces pattern qui m'échappent (étant donné que l'article en question est la 1ère réponse qui arrive quand on cherche "design pattern C++" sur google :p)
    La fabrique n'est pas le meilleure qu'il existe, j'en avais écrit une autre: cf ici. au passage avec des pointeurs intelligents près

    Citation Envoyé par koala01 Voir le message

    Par contre, il est vrai que l'auteur n'a pas penser à utiliser CRTP en ce qui concerne le singleton templatisé
    Comment ca ?

  9. #9
    Membre chevronné
    Avatar de Goten
    Profil pro
    Inscrit en
    Juillet 2008
    Messages
    1 580
    Détails du profil
    Informations personnelles :
    Âge : 34
    Localisation : France

    Informations forums :
    Inscription : Juillet 2008
    Messages : 1 580
    Points : 2 205
    Points
    2 205
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,


    Par contre, il est vrai que l'auteur n'a pas penser à utiliser CRTP en ce qui concerne le singleton templatisé
    Il me semble bien que si, justement il utilise le CRTP non?

Discussions similaires

  1. Meilleur livre sur les design patterns en Java?
    Par JFortranDoc dans le forum Logging
    Réponses: 5
    Dernier message: 15/06/2006, 02h19
  2. Quelques questions sur les LOB
    Par Wurlitzer dans le forum Oracle
    Réponses: 2
    Dernier message: 14/06/2006, 18h32
  3. Quelques questions sur les threads
    Par benj63 dans le forum C++Builder
    Réponses: 28
    Dernier message: 21/11/2005, 14h27
  4. Recherche de doc sur les Design pattern
    Par MicroPuce dans le forum Langages de programmation
    Réponses: 4
    Dernier message: 09/05/2005, 16h58

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