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 :

Choix de pattern


Sujet :

C++

  1. #1
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 30
    Points : 18
    Points
    18
    Par défaut Choix de pattern
    Bonjour,

    J'ai un petit probléme de conception. En effet, j'ai besoin de gérer un groupe d'objet (de nature diverse avec l'héritage) mais je n'y arrive pas.

    Les deux contraintes sont la vitesse et l'automatisation.
    L'ideal c'est que les objets soient automatiquement enregistrés dans le manager grâce à leur constructeur et qu'ils y partent grâce à leur destructeur.

    J'ai un truc comme ça :
    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
     
    //Marche pas, seg fault.
    class Foo;
     
    class Manager
    {
    boost::ptr_list< Foo > Foo_List;
     
    public :
     
       void Add_Foo( foo* );//Ajout d'un objet.
     
       void Del_Foo( boost::ptr_list< Foo >::iterator );//Suppr d'un objet.
    };
     
     
     
     
    class Foo
    {
    public :
     
       Foo( Manager * M )
        {M->Add_Foo(this);}
     
      ~Foo()
        {M->Del_Foo( it_Recuperé_Avant );}
    };

    La list est utile car les objets sont détruits et ajoutés dans un ordre quelconque et régulièrement.

    Le code n'est pas utile car je ne cherche pas d'erreur dans le code mais dans la conception.



    Est-ce qu'il y a un pattern pour ça ?
    Sinon, une petite piste svp.

    Cordialement Julien

  2. #2
    Membre averti Avatar de Nogane
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    241
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 241
    Points : 323
    Points
    323
    Par défaut
    Bonjours,
    En effet cette première approche me semble un peu dangereuse. Tout d'abord parque tes objets Foo n'ont pas a connaitre leur manager. Mais surtout parque c'est ta ptr_list qui gère la durée de vie de tes objets. Donc il n'y a aucune raison qu'il soit détruit par autre chose que la ptr_list.(Alors que la c'est le destructeur de Foo qui appelle sa suppression de la liste, et donc... sa destruction...)

    Dans ce genre de situation j'ai tendance a utiliser des conteneur de shared_ptr plutôt que des ptr_container.
    Pour la création d'un Foo deux solution, ou tu ajoute ton objet toi même dans le manager:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    shared_ptr<Foo> newFoo(new Foo(ID));
    FooManager::Add(newFoo);
    Ou tu donne la possibilité a ton Manager de créer l'objet si il ne l'as pas déjà:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    shared_ptr<Foo> newFoo = FooManager::Get(ID);
    Perso, je suis un adepte de la deuxième solution.

    Pour la destruction, tu ne doit surtout pas détruire toi même ton objet. Deux solution:
    Ou tu demande au manager de s'en débarrasser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FooManager::Remove(ID);
    Ou tu t'arrange pour qu'il le supprime tout seul quand le Foo ne sert plus. Toute la difficulté est de déterminer si l'objet ne sert plus. La solution la plus simple étant de se dire que si il n'y as plus de shared_ptr qui pointent dessus, c'est qu'il ne sert plus. Pour ca on peut par exemple faire un conteneur de weak_ptr, plutot que de shared_ptr, est fair un lock() dans la methode Get().

    Je ne sait pas si il y as un pattern pour ca. D'autre personnes auront peut-être d'autre suggestion...

  3. #3
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 49
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Pour ma part, je dériverais mes classes "Foo" d'une classe de base sachant s'enregistrer dans un manager, enregistrement effectué via un appel au constructeur ancêtre...

    Ainsi, au moins, tu ne dupliques pas le code d'enregistrement (ce qui est bien), et surtout tu peux modifier cet enregistrement SANS retoucher au code spécifique des classes "Foo"... Ni ajouter dedans un quelconque paramètre "Manager", car tout est fait dans la classe de base.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  4. #4
    Membre à l'essai
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    30
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 30
    Points : 18
    Points
    18
    Par défaut
    Merci pour vos réponses, ça marche \o/

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

    Informations professionnelles :
    Activité : aucun

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

    Je serais plutôt d'avis de travailler en réalité avec trois classes pour gerer l'existence de tes objets:
    une classe factory, qui dispose d'une liste d'objet clonable et qui connait le manager, qui travaillerait sur un principe proche de
    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
    class Manager;
     
    class Factory
    {
         typedef std::map<TypeId, BaseType*> map;
         typedef typename map::const_iterator const_iterator;
         public:
             static BaseType* create(TypeId  id)
             { 
                 /* éventuellement
                 assert(manager_!=0);  
                 */
                 const_iterator it=items_.find(id);
                 if(it !=items_.end())
                 {
                     BaseType* temp= (*it).second->clone();
                     manager_->registerItem(temp);
                     return temp;
                 }
                 return NULL;
     
             }
             /* ne sera utile que si tu envisage d'avoir plusieurs managers
              * différents et lors de l'initialisation de ton application
              */
             static void changeManager(Manager * man)
             {
                 assert(man!=0);
                 manager_=man;
             }
        private:
            static map items_;
            static Manager * manager_;
    };
    une classe "assassin" qui ne connait que le manager et qui fonctionne sous une forme proche de proche de
    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
    class Manager;
    class ItemKiller
    {
        public:
            static void killItem(BaseType* b)
            {
                 /* éventuellement
                 assert(manager_!=0);  
                 */
                 manager_->unregisterItem(b);
                 delete b;
            }  
             static void changeManager(Manager * man)
             {
                 assert(man!=0);
                 manager_=man;
             }
        private:
            static Manager * manager_;
    };
    Et, enfin, la classe Manager elle-même qui se contente d'enregistrer et de "désenregistrer" les différents objets au fur et à mesure:
    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
    class Manager
    {
        typedef std::list<BaseType*> list;
        public:
            typedef typename list::iterator iterator;
            typedef typename list::const_iterator const_iterator;
            void registerItem(BaseType* b)
            {
                items_.push_back(b);
            }
            void unregisterItem(BaseType* b)
            {
                const_iterator it= items_.begin();
                while it!=items_.end() && (*it)!=b;
                    ++it;
                if(it!=items_.end())
                    items_.erase(it);
            }
            iterator itemsBegin(){return items_.begin();}
            const_iterator itemsBegin()const{return items_.begin();}
            iterator itemsEnd(){return items_.begin();}
            const_iterator itemsEnd()const{return items_.begin();}
        private:
            list items_;
    };
    Pour comprendre le tout, il "suffit" de savoir que TypeId est le type qui te permet de déterminer l'objet réel qu'il te faut et que la classe BaseType et la classe "ancêtre" de toutes tes classes utiles et qui fournit une interface virtuelle "clone()"

    De cette manière, lors de l'initialisation de ton application, tu crée le manager, la fabrique et l'assassin, et, lors de l'utilisation, tu appelle la fabrique lorsqu'il te faut un objet et l'assassin lorsque tu n'en a plus besoin: Tu es très proche du respect de la loi demeter, et tu respecte scrupuleusement le principe de la responsabilité unique.

    Au final, tu peux modifier n'importe quelle classe sans que cela n'influe fortement sur les autres (il faut "juste" veiller à rester cohérent sur les relations Manager <-->Factory et Manager<-->ItemsKiller)
    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

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

Discussions similaires

  1. Choix de design pattern
    Par velocity dans le forum Général Java
    Réponses: 0
    Dernier message: 25/05/2013, 20h26
  2. choix du pattern
    Par oukacha dans le forum Design Patterns
    Réponses: 2
    Dernier message: 27/04/2012, 20h29
  3. Choix d'implémentation du Pattern Singleton
    Par Sehnsucht dans le forum VB.NET
    Réponses: 1
    Dernier message: 26/07/2010, 09h54
  4. Choix d'un pattern
    Par guiph dans le forum Design Patterns
    Réponses: 8
    Dernier message: 13/10/2008, 10h06
  5. Choix de design pattern
    Par xspartacusx dans le forum Design Patterns
    Réponses: 8
    Dernier message: 12/11/2007, 09h22

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