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

Langage C++ Discussion :

Mettre à jour une classe quand une autre classe est modifée


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par défaut Mettre à jour une classe quand une autre classe est modifée
    Bonjour,

    J'ai un objet A composé de plusieurs objet B. Chaque objet B à un attribut 'profit'. J'aimerais avoir un attribut dans A qui donne la somme des profits des objets B qui le compose.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class A
    {
       private:
          double _profitTotal;
          QList<B> _listB;
    };
     
    class B
    {
       private:
          double _profit;
    };
    Comment mettre à jour le profit total de A à chaque modification de B ?

    Merci.

  2. #2
    Inactif  


    Homme Profil pro
    Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Inscrit en
    Décembre 2011
    Messages
    9 026
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : France, Loire (Rhône Alpes)

    Informations professionnelles :
    Activité : Doctorant sécurité informatique — Diplômé master Droit/Économie/Gestion
    Secteur : Enseignement

    Informations forums :
    Inscription : Décembre 2011
    Messages : 9 026
    Par défaut
    Bonjour,

    Essaye de rechercher les design pattern "observeur-observable"

  3. #3
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par défaut
    Les objets B doivent pointer vers A. Y'a pas mieux ?

  4. #4
    Membre Expert
    Avatar de Klaim
    Homme Profil pro
    Développeur de jeux vidéo
    Inscrit en
    Août 2004
    Messages
    1 717
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur de jeux vidéo
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 1 717
    Par défaut
    Le pattern observer aurait ete une solution mais franchement dans ce genre de cas pourquoi faire compliquer?

    Ca depends quasimment de comment tu accedes a B.

    Si tu peux faire en sorte qu'acceder a B passe forcement par acceder a A, alors c'est simple.

    Si le code externe a A peut avoir des references a B, alors A doit observer tous les B, ou alors B doit observer A (les deux marchent mais selon les cas n'auront pas les memes implications de performance theorique).

    Dis nous d'abord

    1. comment actuellement tu accedes aux B pour les modifier?
    2. est-ce que tu as le droit de modifier cet acces?

    La question deux peut nous permettre de trouver une solution sans pattern observer, par exemple en faisant que A ne laisse acceder aux B que via un "visiteur".

  5. #5
    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,

    Il faudra, de toutes façons, qu'il y ait "quelque part" la possibilité de mettre un objet de type A en relation avec un objet de type B...

    Mais il n'est peut etre pas de la responsabilité de l'objet de type B de veiller à ce que l'objet de type A soit mis à jour

    A ce moment là, l'idée est sans doute d'utiliser la partie MC de ce que l'on appelle le partron Model/vue/contrôleur (donc, si tu as bien suivi: la partie "Modèle" et la partie "Contrôleur" , étant donné qu'il faudra sans doute prendre la décision de modifier ton objet de type B et s'assurer que l'on n'essaye pas de le faire de manière incongrue.

    L'idée est alors d'avoir un "troisième larron" (ca tombe bien, la lettre suivante est C qui pourrait passer pour "contrôleur" ) qui disposera de l'objet de type A qui contient (ou qui est destiné à contenir) l'objet de type B et de l'objet de type B lui-même et qui:
    vérifiera si les modifications que l'on s'apprête à appliquer à l'objet de type B sont "valides"
    apportera les modification à l'objet de type B
    demandera à l'objet de type A de se mettre à jour --ce qui peut etre fait, par exemple, en rajoutant l'objet de type B nouvellement créé -- en recalculant (entres autres) le total des éléments qu'il contient.

    Cela peut très bien se faire sous la forme de plusieurs fonctions libres, sous une forme 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
    /* cette fonction vérifie si on peut apporter la modification à l'objet de 
     * type B
     *
     * @param[in] b: L'objet de type B à modifier
     * @param[in] modif: la modification à apporter
     * @return true si la modification peut etre apportée, false autrement
     */
    bool modificationValide(B const & b , ModifType const & modif){
        /* toute la logique nécessaire pour s'assurer que la modification
         * est correcte
         */
    }
    /* Applique la modification de manière effective et prend les mesures
     * adéquates
     * @param[in,out] liste: la liste des objet de type B qui doit être mise à  jour
     * @param[in,out] b : l'objet de type B modifier
     * @param[in] modif : la modification à apporter
     *
     */
    void modifieLobjet(A & liste, B & b, ModifType const & modif){
        if(modificationValide(b, modif){
            /* -1 : modifier b */
            b.modify(modif);
            /* -2 : mettre liste à jour */
            liste.update(/* b??? */);
        }else{
            /* Que fait on si on peut pas ??? */
        }
    }
    Mais tu peux également créer carrément une classe qui aura les mêmes comportements
    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

  6. #6
    Membre très actif
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2012
    Messages
    538
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2012
    Messages : 538
    Par défaut
    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
    class Observeur
    {
        public:
            virtual void majProfit(double inProfit) = 0;
    };
     
    class Observer
    {
        private:
            Observeur * _observeurs;
     
        public:
            void setObserveurs(Observeur * observeur) { _observeurs = observeur; }
     
            void avertirObserveurs(double inProfit)
            {	
                _observeurs.majProfit(inProfit);
            }
    };
     
     
     
    class A : public Observeur
    {
        private:
            double _profitTotal;
            QList<B> _listB;
     
        public:
    	   A() { _profitTotal = 0; }
     
    	   void ajouterB()
    	   {
    	        B b;
                    b.ajouterObserver(this);
    	        _listB.push_back(b);
    	   }
     
    	   void majProfit(double inProfit) { _profitTotal += inProfit; }
    };
     
    class B : public Observer
    {
        private:
            double _profit;
     
    	public:
                B();
     
    	    void setProfit(double inProfit) { _profit = inProfit; avertirObserveurs(inProfit); }
    };
    ou alors

    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
    class A
    {
        private:
            double _profitTotal;
            QList<B> _listB;
     
        public:
    	   A() { _profitTotal = 0; }
     
    	   void ajouterB()
    	   {
                    B b(this);
    	        _listB.push_back(b);
    	   }
     
    	   void majProfit(double inProfit) { _profitTotal += inProfit; }
    };
     
    class B
    {
        private:
            A * _a;
            double _profit;
     
    	public:
    		B(A * inA) { _a = inA; }
     
    	    void setProfit(double inProfit) { _profit = inProfit; A.majProfit(inProfit); }
    };

  7. #7
    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
    Citation Envoyé par CliffeCSTL Voir le message
    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
    class Observeur
    {
        public:
            virtual void majProfit(double inProfit) = 0;
    };
     
    class Observer
    {
        private:
            Observeur * _observeurs;
     
        public:
            void setObserveurs(Observeur * observeur) { _observeurs = observeur; }
     
            void avertirObserveurs(double inProfit)
            {	
                _observeurs.majProfit(inProfit);
            }
    };
     
     
     
    class A : public Observeur
    {
        private:
            double _profitTotal;
            QList<B> _listB;
     
        public:
    	   A() { _profitTotal = 0; }
     
    	   void ajouterB()
    	   {
    	        B b;
                    b.ajouterObserver(this);
    	        _listB.push_back(b);
    	   }
     
    	   void majProfit(double inProfit) { _profitTotal += inProfit; }
    };
     
    class B : public Observer
    {
        private:
            double _profit;
     
    	public:
                B();
     
    	    void setProfit(double inProfit) { _profit = inProfit; avertirObserveurs(inProfit); }
    };
    Légal du point de vue du code, mais très mauvais du point de vue de la conception!!!

    Ce code implique en effet que tu peux "mélanger" des pointeurs vers des objet de type A et des pointeurs vers des objets de type B dans une seule et meme collection, en les faisant passer pour "des pointeurs vers des objets de type observateur", alors que, s'il y a bel et bien une relation entre les deux types d'objets, ce n'est certainement pas une relation de "fraternité" comme celle que l'on obtient avec l'héritage.

    Si, à un moment donné, au fur et à mesure des évolutions de ton projets, tu en viens à vouloir une classe "MégaProfit" (par exemple, parce que tu veux pouvoir calculer les profits de différentes succursales et les maintenir dans différentes listes de profits "nationaux" qui seront elles même gérées par une liste de profit "mondiale") qui hérite aussi bien de A que de B, tu te retrouveras dans la panade avec l'obligation de passer par l'héritage virtuel
    ou alors

    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
    class A
    {
        private:
            double _profitTotal;
            QList<B> _listB;
     
        public:
    	   A() { _profitTotal = 0; }
     
    	   void ajouterB()
    	   {
                    B b(this);
    	        _listB.push_back(b);
    	   }
     
    	   void majProfit(double inProfit) { _profitTotal += inProfit; }
    };
     
    class B
    {
        private:
            A * _a;
            double _profit;
     
    	public:
    		B(A * inA) { _a = inA; }
     
    	    void setProfit(double inProfit) { _profit = inProfit; A.majProfit(inProfit); }
    };
    Sans doute moins mauvais du point de vue de la conception, mais tu force une dépendance de B vers A qui n'a pas forcément lieu d'être. Après tout, pourquoi B devrait il connaitre obligatoirement le A qui le contient

    Que va-t-il se passer si, pour une raison ou une autre, tu venais décider de changer ton objet de liste

    Soit, tu devras recréer un nouvel objet identique (en perdant l'unicité référentielle !!!) dans la nouvelle liste avant de le supprimer de l'ancienne, soit tu devrais prévoir, quelle horreur!!!, un mutateur pour le pointeur sur A (oui, j'ai déjà grandement résisté à la tentation de crier au scandale quand j'ai vu tous les mutateurs que tu plaçais dans ton code )

    L'idée est donc que si tu as une relation à sens unique "un (objet de type A) à plusieurs (objets de type B)", il ne sert strictement à rien de la transformer, dans ton programme, en une relation bi directionnelle.

    Pour y arriver, l'idée est toute simple: créer un troisième type, qui n'est ni un A ni un B, qui soit capable, quand une modification du B est acceptée de demander au A qui le contient de se mettre à jour.

    Cela aura, de plus, l'énorme avantage de donner clairement "à quelque chose" la responsabilité de s'assurer que les modifications que l'on peut envisager d'apporter au B sont autorisées.

    Et c'est d'autant plus vrai que, de prime abord, la classe B aura sémantique d'entité dans le sens où chaque objet doit pouvoir être identifié de manière unique et non ambigüe (sans compter que l'on voudra peut etre, à un moment ou à un autre, pouvoir faire la distinction entre différentes sources de profit ) , avec tout ce que cela implique, dont (essentiellement) le fait que les objets de types B devraient, idéalement, n'être ni copiables ni assignables, et donc, sans doute, la nécessité de manipuler, au sein de A, les objets de type B sous la forme de pointeurs (de préférence intelligents), et donc que A serait, de toutes manières, le "propriétaire légal" de tous les objets de type B qu'il peut contenir.

    Nous pourrions donc parfaitement nous trouver au final avec quelque chose qui serait fort 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
    35
    36
    37
    38
    39
    40
    41
    class B{
        frien class BCreator;
        public:
            //C++11 inside :D
            B(const & B) = delete;
            B& operator=(B const &) =delete;
            //virtual ~B(){}
            void addToProfit(double value){profit_+= value;} 
            void substractFromProfit(double value){profit_+= value;} 
            int id() const{return id_;}
            double realProfit() const{return profit_;}
        private:
            B(int id, double profit):id_(id), profit_(profit){}
            int id_; // un identifiant unique
            double profit_;
    };
     
    class A{
        public:
            A():allProfits(),summ_(0.0){}
            void addProfit(B* b){
                allProfits_[b->id()].reset(b);
                summ_+=b->realProfit();
            }
            B* profit(int id){
                auto it=allProfits_.find(id);
                if(it!=allProfits_.end())
                    return it->second.get();
                return nullptr;
            }
            void update(){
                summ_=0.0;
                for (auto & it:allProfits){
                    summ_+=it.second->realProfit();
                }
            }
            int nextId() const{return allProfits_.size();}
        private:
            std::map<int, std::unique_ptr<B>> allProfits_;
            double summ_;
    };
    et le troisième larron qui prendrait la forme de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class BCreator{
        public:
            BCreator(A & a):a_(a){}
            void addProfit(double profit){
                 a_.addProfit(new B(a.nextId(),profit));
            }
        private:
            A & a_;
    };
    ou encore 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
    class ProfitModifier{
     
            BCreator(A & a):a_(a){}
            bool augmentProfit(int id, double profit){
                B* item=a_.profit(id);
                if(item!=nullptr){
                    item->addToProfit(profit);
                    a_.update();
                    return true;
                }
                return false;
            }
            void substractProfit(int id, double profit){
                B* item=a_.profit(id);
                if(item!=nullptr){
                    item->substractFromProfit(profit);
                    a_.update();
                    return true;
                }
                return false;
            }
        private:
            A & a_;
    };
    qui auraient, en plus, l'énorme avantage de faire en sorte que l'utilisateur n'ait aucun besoin de connaitre exactement la classe B pour la manipuler, à partir du moment où (pour ce qui est de ProfitModifier) il dispose de l'identifiant de l'objet à modifier
    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

Discussions similaires

  1. Réponses: 4
    Dernier message: 03/07/2008, 15h53
  2. Recherche une valeur d'une cellule dans une colonne d'une autre feuille
    Par kourria dans le forum Macros et VBA Excel
    Réponses: 8
    Dernier message: 21/06/2007, 13h48
  3. Réponses: 1
    Dernier message: 19/02/2007, 16h58
  4. Comment mettre à jour 1 champ d'une table via une autre tabl
    Par cpasmoibiensur dans le forum MS SQL Server
    Réponses: 1
    Dernier message: 05/02/2006, 13h33

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