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 :

Problème de conception : héritage VS composition VS… séparation


Sujet :

C++

  1. #1
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut Problème de conception : héritage VS composition VS… séparation
    Bonjour,
    Comme dit dans le titre, j'ai un petit problème de conception.
    Enfin c'est plus une interrogation qu'un problème, mais bon...

    En fait, j'ai un couple de valeurs, avec une sémantique précise.
    Pour certains cas, j'aimerais augmenter ce couple avec une troisième valeur.
    La sémantique du couple restant la même, mais avec la nouvelle valeur le tout devient un triplet à part entière.

    D'où la seconde partie de la question dans le titre.
    Alors à votre avis, 1, 2 ou 3 ?

    Code Couple : 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
    class couple
    {
     
      public:
        typedef ... first_type;
        typedef ... second_type;
     
      private:
        first_type m_first;
        second_type m_second;
     
      public:
        couple() = default;
     
        couple(first_type const& e1, second_type const& e2) : m_first(e1), m_second(e2)
        {}
     
        first_type const& get_first() const
        { return m_first; }
     
        second_type const& get_second() const
        { return m_second; }
     
        void get(first_type& e1, second_type& e2) const
        {
            e1 = m_first;
            e2 = m_second;
        }
     
        void reset()
        {
            m_first = first_type();
            m_second = second_type();
        }
     
        void set(first_type const& e1, second_type const& e2)
        {
            m_first = e1;
            m_second = e2;
        }
     
    }; // class couple
     
     
    bool operator == (couple const& lhs, couple const& rhs)
    {
        return ( (lhs.get_first() == rhs.get_first()) && (lhs.get_second() == rhs.get_second()) );
    }
     
     
    bool operator < (couple const& lhs, couple const& rhs)
    {
        return ( (lhs.get_first() < rhs.get_first()) ||
               ( (lhs.get_first() == rhs.get_first()) && (lhs.get_second() < rhs.get_second()) ));
    }

    Code Héritage : 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
    class triplet : private couple
    {
     
      public:
        typedef couple::first_type first_type;
        typedef couple::second_type second_type;
        typedef ... third_type;
     
      private:
        third_type m_third;
     
      public:
        triplet() = default;
     
        triplet(first_type const& e1, second_type const& e2, third_type const& e3) : couple(e1, e2), m_third(e3)
        {}
     
        using couple::get_first;
     
        using couple::get_second;
     
        third_type const& get_third() const
        { return m_third; }
     
        void get(first_type& e1, second_type& e2, third_type& e3) const
        {
            couple::get(e1, e2);
            e3 = m_third;
        }
     
        void reset()
        {
            couple::reset();
            m_third = third_type();
        }
     
        void set(first_type const& e1, second_type const& e2, third_type const& e3)
        {
            couple::set(e1, e2);
            m_third = e3;
        }
     
    }; // class triplet
     
     
    bool operator == (triplet const& lhs, triplet const& rhs)
    {
        return ( (lhs.get_first() == rhs.get_first()) &&
                 (lhs.get_second() == rhs.get_second()) &&
                 (lhs.get_third() == rhs.get_third()) );
    }
     
     
    bool operator < (triplet const& lhs, triplet const& rhs)
    {
        if (lhs.get_first() < rhs.get_first())
            return true;
     
        if (rhs.get_first() == lhs.get_first()) {
            if (lhs.get_second() < rhs.get_second())
                return true;
            return ( (lhs.get_second() == rhs.get_second()) && (lhs.get_third() < rhs.get_third()) );
        }
     
        return false;
    }
    Code Composition : 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
    class triplet
    {
     
      public:
        typedef couple::first_type first_type;
        typedef couple::second_type second_type;
        typedef ... third_type;
     
      private:
        couple m_couple;
        third_type m_third;
     
      public:
        triplet() = default;
     
        triplet(first_type const& e1, second_type const& e2, third_type const& e3) : m_couple(e1, e2), m_third(e3)
        {}
     
        first_type const& get_first() const
        { return m_couple.get_first(); }
     
        second_type const& get_second() const
        { return m_couple.get_second(); }
     
        third_type const& get_third() const
        { return m_third; }
     
        void get(first_type& e1, second_type& e2, third_type& e3) const
        {
            m_couple.get(e1, e2);
            e3 = m_third;
        }
     
        void reset()
        {
            m_couple.reset();
            m_third = third_type();
        }
     
        void set(first_type const& e1, second_type const& e2, third_type const& e3)
        {
            m_couple.set(e1, e2);
            m_third = e3;
        }
     
    }; // class triplet
     
     
    bool operator == (triplet const& lhs, triplet const& rhs)
    {
        return ( (lhs.get_first() == rhs.get_first()) &&
                 (lhs.get_second() == rhs.get_second()) &&
                 (lhs.get_third() == rhs.get_third()) );
    }
     
     
    bool operator < (triplet const& lhs, triplet const& rhs)
    {
        if (lhs.get_first() < rhs.get_first())
            return true;
     
        if (rhs.get_first() == lhs.get_first()) {
            if (lhs.get_second() < rhs.get_second())
                return true;
            return ( (lhs.get_second() == rhs.get_second()) && (lhs.get_third() < rhs.get_third()) );
        }
     
        return false;
    }
    Code Séparation : 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
    class triplet
    {
     
      public:
        typedef ... first_type;
        typedef ... second_type;
        typedef ... third_type;
     
      private:
        first_type m_first;
        second_type m_second;
        third_type m_third;
     
      public:
        triplet() = default;
     
        triplet(first_type const& e1, second_type const& e2, third_type const& e3) : m_first(e1), m_second(e2), m_third(e3)
        {}
     
        first_type const& get_first() const
        { return m_first; }
     
        second_type const& get_second() const
        { return m_second; }
     
        third_type const& get_third() const
        { return m_third; }
     
        void get(first_type& e1, second_type& e2, third_type& e3) const
        {
            e1 = m_first;
            e2 = m_second;
            e3 = m_third;
        }
     
        void reset()
        {
            m_first = first_type();
            m_second = second_type();
            m_third = third_type();
        }
     
        void set(first_type const& e1, second_type const& e2, third_type const& e3)
        {
            m_first = e1;
            m_second = e2;
            m_third = e3;
        }
     
    }; // class triplet
     
     
    bool operator == (triplet const& lhs, triplet const& rhs)
    {
        return ( (lhs.get_first() == rhs.get_first()) &&
                 (lhs.get_second() == rhs.get_second()) &&
                 (lhs.get_third() == rhs.get_third()) );
    }
     
     
    bool operator < (triplet const& lhs, triplet const& rhs)
    {
        if (lhs.get_first() < rhs.get_first())
            return true;
     
        if (rhs.get_first() == lhs.get_first()) {
            if (lhs.get_second() < rhs.get_second())
                return true;
            return ( (lhs.get_second() == rhs.get_second()) && (lhs.get_third() < rhs.get_third()) );
        }
     
        return false;
    }

    Il me semble qu'il vaudrait mieux utiliser le troisième code, mais je me demandais s'il n'y avait pas une possibilité de réutiliser le code de la classe couple tout en restant cohérent/correct.

  2. #2
    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
    Points : 3 344
    Points
    3 344
    Par défaut
    Séparation oui a priori, mais il manque au triplet de quoi prendre des valeurs du couple, pour pouvoir travailler avec les deux, non?

    Enfin je dis ça mais c'est peut être du feature creep.

  3. #3
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Tu veux dire quelque chose comme ceci ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    triplet::triplet(couple const& c, third_type const& e3);
    void triplet::set(couple const& c, third_type const& e3);
    Citation Envoyé par Klaim Voir le message
    Enfin je dis ça mais c'est peut être du feature creep.
    Euh...
    Pardon ?

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

    Informations professionnelles :
    Activité : aucun

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

    Pour moi, séparation, sans aucun doute...

    On pourrait reporter cela aux points 2D par rapport aux points 3D...

    Ce sont bel et bien des points, qui manipulent le meme type de valeur, mais il est hors de question de faire hériter un point 3D d'un point 2D, ne serait-ce que parce que leur utilisation sera tout à fait différente

    Dans le meilleur des cas, tu peux envisager de fournir un opérateur de conversion triplet-> couple, mais...
    1. quelle paire de ton triplet vas tu utiliser (1/2, 1/3, 2/3)
    2. Est ce que cela a un sens
    3. Est-ce qu'on peut se contenter de prendre une pair existante, ou faudra-t-il "transormer" les donnée


    Mais, je vais surtout dire ce qui me fait renoncer aux autres possibilités
    1. L'héritage public: on ne peut pas dire d'après LSP qu'un triplet est un couple, tout comme on ne peut pas dire qu'un carré est un rectangle (bien que ce soit mathématiquement le cas)
    2. L'héritage privé : on ne peut pas estimer qu'un triplet soit implémenté en terme de couple... cela n'aurait aucun sens
    3. La composition: cela nous obligerait à des indirections supplémentaires inutiles (avec nécessité de créer des fonctions "raccourcis" pour respecter demeter)
    Non, décidément, rien ne vaut la séparation des pouvoirs

  5. #5
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Dans le meilleur des cas, tu peux envisager de fournir un opérateur de conversion triplet-> couple, mais...
    1. quelle paire de ton triplet vas tu utiliser (1/2, 1/3, 2/3)
    2. Est ce que cela a un sens
    3. Est-ce qu'on peut se contenter de prendre une pair existante, ou faudra-t-il "transormer" les donnée
    1. Le type des éléments ne laisse pas le choix... ce n'est certes pas clair ici, mais ils sont tous différents (dans mon cas particulier en tout cas).
    2. Tout à fait.
    3. Une petite transformation sera nécessaire.

    Pour plus de précisions, je te renvoie à l'exemple donné ici.

    Citation Envoyé par koala01 Voir le message
    Mais, je vais surtout dire ce qui me fait renoncer aux autres possibilités
    1. L'héritage public: on ne peut pas dire d'après LSP qu'un triplet est un couple, tout comme on ne peut pas dire qu'un carré est un rectangle (bien que ce soit mathématiquement le cas)
    2. L'héritage privé : on ne peut pas estimer qu'un triplet soit implémenté en terme de couple... cela n'aurait aucun sens
    3. La composition: cela nous obligerait à des indirections supplémentaires inutiles (avec nécessité de créer des fonctions "raccourcis" pour respecter demeter)
    1. C'est bien pour cela que je ne l'ai pas proposé.
    2. Je suis tout à fait d'accord. Disons que je me disais que l'on peut considérer que si l'on greffe une troisième donnée à un couple, ça devient un triplet... Le tout étant de savoir comment représenter correctement cette greffe...
    3. Certes...


    Quoi qu'il en soit, merci à vous de confirmer ce que je pensais.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Je n'attendais pas vraiment de réponse à mes remarques concernant l'opérateur de conversion, c'était essentiellement pour attirer l'attention sur ce qui peut te faire décider de ne pas en créer

    Quand à l'héritage public, je ne l'ai mis que pour etre complet quant aux possibilités qui nous étaient données

  7. #7
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Oh tiens, pendant que j'y pense, à propos de using :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class triplet : private couple
    {
     
        (...)
     
      public:
        using couple::get_first;
     
    //******************//
     
        first_type const& get_first() const
        { return couple::get_first(); }
     
    };
    Fondamentalement, quelles sont les différences entre les deux écritures ?
    Point de vue compilateur/éditeur de lien, j'entends.
    L'une d'elle est-elle plus rapide ? plus efficace ? plus gourmande en ressources ?
    Si la fonction redéfinie est inlinée ? ne l'est pas ?

  8. #8
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Je n'attendais pas vraiment de réponse à mes remarques concernant l'opérateur de conversion, c'était essentiellement pour attirer l'attention sur ce qui peut te faire décider de ne pas en créer
    Ouais, mais j'avais envie de répondre...
    Et finalement, ça m'a plutôt donné envie d'en créer un...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Steph_ng8 Voir le message
    Oh tiens, pendant que j'y pense, à propos de using :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    class triplet : private couple
    {
     
        (...)
     
      public:
        using couple::get_first;
     
    //******************//
     
        first_type const& get_first() const
        { return couple::get_first(); }
     
    };
    Fondamentalement, quelles sont les différences entre les deux écritures ?
    Point de vue compilateur/éditeur de lien, j'entends.
    L'une d'elle est-elle plus rapide ? plus efficace ? plus gourmande en ressources ?
    Si la fonction redéfinie est inlinée ? ne l'est pas ?
    Il me *semble* (cela demande donc vérification et doit, en attendant, être pris avec toutes les précautions d'usage )que la visibilité n'est utilisée qu'au niveau du compilateur, pour assurer que seul les objets ad-hoc ont accès à une variable ou à une fonction, mais qu'il n'y a aucune différence (hormis le mangeling du symbole ) au niveau de la mémoire...

    J'aurais donc tendance à dire que les deux sont parfaitement équivalent en terme de rapidité : la directive using disant au compilateur "ce que je t'ai dit qu'il fallait protéger (en le mettant privé), ben, je veux que tu le considères comme public / protégé" la fonction inline étant équivalente à dire "en fait, je rajoute une fonction pour la facilité, mais tu dois en réalité appeler telle fonction"

    La seule certitude étant que tu perdra le temps de l'appel de la fonction si tu ne la rend pas inline

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Même l'héritage privé de couple par triplet me dérange. J'aurais probablement plus vu une base commune à couple et à triplet contenant le code factorisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct tuple_impl;
    struct couple : private tuple_impl;
    struct triplet : private tuple_impl;

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 627
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    Salut,
    Même l'héritage privé de couple par triplet me dérange. J'aurais probablement plus vu une base commune à couple et à triplet contenant le code factorisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    struct tuple_impl;
    struct couple : private tuple_impl;
    struct triplet : private tuple_impl;
    Et même ainsi, je t'avouerai que je ne suis pas sur du tout d'y voir un quelconque intérêt

    Comme je l'ai dit dans ma première intervention :
    L'héritage privé : on ne peut pas estimer qu'un triplet soit implémenté en terme de couple... cela n'aurait aucun sens
    Même si c'est en terme de tuple_impl en l'occurrence

  12. #12
    Membre éprouvé Avatar de Steph_ng8
    Homme Profil pro
    Doctorant en Informatique
    Inscrit en
    Septembre 2010
    Messages
    677
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Doctorant en Informatique

    Informations forums :
    Inscription : Septembre 2010
    Messages : 677
    Points : 997
    Points
    997
    Par défaut
    Citation Envoyé par 3DArchi Voir le message
    J'aurais probablement plus vu une base commune à couple et à triplet contenant le code factorisé :
    Ah ouais, pas con...

    Citation Envoyé par koala01 Voir le message
    Et même ainsi, je t'avouerai que je ne suis pas sur du tout d'y voir un quelconque intérêt
    Réflexion faite...

    Bien.
    Merci de vos interventions, toujours aussi enrichissantes.

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

Discussions similaires

  1. [Composite] [Java] problème de conception, multi héritage, composite ?
    Par phoenix_stealer dans le forum Design Patterns
    Réponses: 2
    Dernier message: 13/11/2013, 17h47
  2. Problème de conception avec héritage
    Par oodini dans le forum C++
    Réponses: 3
    Dernier message: 24/01/2013, 11h43
  3. Problème de conception Composite dans un View
    Par kkt8 dans le forum SWT/JFace
    Réponses: 2
    Dernier message: 24/09/2012, 11h25
  4. Problème de conception : Héritage et template
    Par Awakening dans le forum C++
    Réponses: 7
    Dernier message: 06/09/2010, 19h22
  5. Problème de conceptions de tables
    Par dtavan dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 23/05/2004, 23h13

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