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 :

Que pensez-vous de la loi de Demeter ?


Sujet :

Langage C++

  1. #41
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2006
    Messages : 51
    Points : 64
    Points
    64
    Par défaut
    @Jean-Marc.Bourguet
    Pour moi quand le couplage est fort c'est qu'il doit y avoir une raison, et cette raison est certainement le pattern GRASP "Forte Cohésion" => http://en.wikipedia.org/wiki/GRASP_%...#High_Cohesion
    Et justement ça tombe bien; Oncle Bob parle des Common Closure Principle et Common Reuse Principle qui vont bien avec ce pattern Forte Cohésion => http://butunclebob.com/ArticleS.Uncl...rinciplesOfOod

  2. #42
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    Je me demande si la cause de ma gene ne serait pas que, dans les domaines ou j'ai travaille, la classe est un niveau de decoupage trop fin pour ce genre de regles. (Autrement dit, je crois comprendre l'objectif, il me semble louable, mais le niveau me semble inadapte).
    Cette phrase me semble pleine de sens. Appliquer ce principe au niveau du module, de la bibliothèque, ne me poserait pas vraiment de problème. L'appliquer au niveau de la classe me semble plus douteux, j'ai un peu plus de mal à l'envisager ainsi.

    Il est un peu dommage que ce niveau supérieur n'ait pas vraiment d'existence en C++, mais soit juste une convention entre développeurs.

  3. #43
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par Jean-Marc.Bourguet Voir le message
    C'est peut-etre lie a mon domaine d'application, mais ca me semblerait extremement artificiel. Il y a des classes qui sont intrinsequement liees et vouloir les decoupler n'a absolument aucun sens.

    Je me demande si la cause de ma gene ne serait pas que, dans les domaines ou j'ai travaille, la classe est un niveau de decoupage trop fin pour ce genre de regles. (Autrement dit, je crois comprendre l'objectif, il me semble louable, mais le niveau me semble inadapte).
    La règle de "pas de référence circulaire au niveau des classes" a autant de sens qu'au niveau du package. En fait, c'est un corolaire du principe d'inversion de dépendance - si une référence circulaire existe, alors l'inversion de dépendance n'est pas possible - et une conséquence directe du principe de responsabilité - si la classe A dépends de B, alors B est une responsabilité de A. Si B dépends aussi de A, alors A est une responsabilité de B. Si les deux conditions sont réunies, ni B ni A ne peuvent avoir d'autre responsabilité selon le principe de responsabilité unique, et logiquement, le code ne fait rien. Pas d'une utilité fameuse tout ça...

    Ce n'est pas tout. Les références circulaires sont aussi préjudiciables à l'application du principe ouvert/fermé - dans le sens ou il devient difficile voire impossible d'étendre du code sans modifier le code existant dès lors que ce qu'on souhaite étendre s'auto-référence.

    Trois des principaux principes de conception objet qui sont malmenés sur les 5 les plus utiles, je trouve que c'est un bon chiffre qui nécessite qu'on s'attarde un peu à ce point particulier

    Globablement d'accord mais la limite est parfois ambigue. Si tu refuses setPosition() mais que tu admets moveTo() (le deux faisant exactement la meme chose), ca ne me gene vraisemblablement pas.
    setPosition() est un accesseur, tandis que moveTo() est bel et bien un traitement. Dans les faits, les deux font la même chose, pourtant l'un a du sens, l'autre pas tellement. L'abstraction apportée par le nom moveTo() est plus intéressante au point de vue architecture que celle apportée par setPosition(). J'accepte donc moveTo(), mais pas setPosition().

  4. #44
    Membre du Club
    Profil pro
    Inscrit en
    Avril 2006
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Avril 2006
    Messages : 51
    Points : 64
    Points
    64
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Ce n'est pas vraiment un problème de sémantique mais bien (comme je l'ai dis avant) de taxonomie.
    ...
    Je ne suis pas sûr d'être d'accord / pas d'accord avec toi sur la taxinomie de la loi, j'avoue que tes arguments me font réfléchir, mais je n'arrive pas à trancher encore ce que tu viens de dire.

    Citation Envoyé par Emmanuel Deloget Voir le message
    ...
    La règle de "pas de référence circulaire au niveau des classes" a autant de sens qu'au niveau du package.
    ...
    Ce n'est pas tout. Les références circulaires sont aussi préjudiciables à l'application du principe ouvert/fermé - dans le sens ou il devient difficile voire impossible d'étendre du code sans modifier le code existant dès lors que ce qu'on souhaite étendre s'auto-référence.
    ...
    setPosition() est un accesseur, tandis que moveTo() est bel et bien un traitement. Dans les faits, les deux font la même chose, pourtant l'un a du sens, l'autre pas tellement. L'abstraction apportée par le nom moveTo() est plus intéressante au point de vue architecture que celle apportée par setPosition(). J'accepte donc moveTo(), mais pas setPosition().
    Entièrement d'accord!

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    setPosition() est un accesseur, tandis que moveTo() est bel et bien un traitement. Dans les faits, les deux font la même chose, pourtant l'un a du sens, l'autre pas tellement. L'abstraction apportée par le nom moveTo() est plus intéressante au point de vue architecture que celle apportée par setPosition(). J'accepte donc moveTo(), mais pas setPosition().
    D'autant plus que setPosition() porte, de mon point de vue, une notion "d'instantanéité" que ne porte pas moveTo...

    Avec setPosition(), l'objet est, à un moment donné, à un endroit et, juste après, à un autre (sans oublier qu'il faille penser à calculer la position, qui peut être relative à la position antérieure de l'objet)...

    Avec moveTo(), il me semble plus facile d'envisager de fournir des informations de durée (le déplacement doit prendre XXX "tics") ou de vitesse.

    De plus, il le comportement peut être décliné en "move()" auquel on donne une orientation, un sens (éventuellement une durée et une vitesse), alors qu'il me semble plus difficile de l'envisager avec setPosition()

    Evidemment, cette intervention ne porte que sur la sémantique des termes utilisés, et j'admets également que les deux font au final me même boulot

  6. #46
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    La règle de "pas de référence circulaire au niveau des classes" a autant de sens qu'au niveau du package. En fait, c'est un corolaire du principe d'inversion de dépendance - si une référence circulaire existe, alors l'inversion de dépendance n'est pas possible - et une conséquence directe du principe de responsabilité - si la classe A dépends de B, alors B est une responsabilité de A. Si B dépends aussi de A, alors A est une responsabilité de B. Si les deux conditions sont réunies, ni B ni A ne peuvent avoir d'autre responsabilité selon le principe de responsabilité unique, et logiquement, le code ne fait rien. Pas d'une utilité fameuse tout ça...

    Ce n'est pas tout. Les références circulaires sont aussi préjudiciables à l'application du principe ouvert/fermé - dans le sens ou il devient difficile voire impossible d'étendre du code sans modifier le code existant dès lors que ce qu'on souhaite étendre s'auto-référence.
    Comment mets-tu en place un concept conteneur/itérateur (avec validation des bornes) sans référence circulaire ?

    Ou encore, dans une gestion de graphe avec nœuds et liens, soit un nœud connait ses liens, et un lien connait ses nœuds, soit aucun ne connait les autres, cette connaissance étant centralisée au niveau du graphe lui même. Le design sans référence circulaire est-il meilleur ? Il oblige chaque fonction devant manipuler des liens ou ds nœuds à avoir un paramètre de type graphe. Pour ôter une dépendance circulaire, on a ajouté une dépendance au graphe à plein d'endroit où elle est a priori inutile.

    Non, honnêtement, ces arguments, j'ai du mal à y adhérer.

    Et oui, le principe ouvert/fermé, par exemple, n'a pas de sens pour moi au niveau d'un nœud ou d'un lien. C'est au niveau de l'ensemble du module graphe (avec ses classes graphe, nœud, lien) que je vois l'intérêt de l'appliquer. Ces classes sont trop intriquées pour évoluer indépendamment, et ça ne me choque pas du tout. Là où ça me choquerait, c'est par exemple si je ne pouvais pas les faire évoluer sans modifier tous les clients du graphe, ou si je ne pouvais pas faire évoluer ces clients sans devoir modifier aussi le graphe. Il n'y a pas pour moi de relation client/fournisseur entre ces classes, elles font partie d'un package unique vendu sous blister.

  7. #47
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Loic, c'etait mon texte ca.

  8. #48
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    Ton 7 +/-2 est correcte, certes, mais tu parles toi-même d'éléments. Pas de caractères. 5 à 7 paramètres, on s'en souvient vaguement. 5 à 7 mots dans un identifiants, on s'en souviendra aussi bien - et ça commence à faire un pétard de long identifiant
    Au risque de me répéter, je parlais surtout du nombre de méthode accessible depuis une classe -_-'...

    Citation Envoyé par Emmanuel Deloget Voir le message
    Si j'ai bien compris les rrefs, il ne s'agit pas là d'une des utilisations envisagées - en tout cas, pas comme moyen de contourner l'encapsulation.
    Je me suis un peu emmêlé les pinceaux à ce sujet dans mes post précédent. Non, il ne s'agit pas quelque chose de prévu, mais quelque chose de pratique; un moyen de jeter le flou sur de l'implémentation... C'est de ça qu'il s'agit non ?

    Citation Envoyé par Emmanuel Deloget Voir le message
    Ce n'est pas vraiment un problème de sémantique mais bien (comme je l'ai dis avant) de taxonomie.
    Merci pour le soutien et les infos ^^...

    Citation Envoyé par koala01 Voir le message
    Par contre, si traitement1() agit, pour faire simple, comme un getter "amélioré" et renvoie un membre de l'objet, cela me semble déjà beaucoup plus choquant.
    Oui si on renvoie une lvalue (lref ou pointeur); non si on renvoie une rvalue (rref ou valeur). Evidemment, la rref révèle un peu la classe; mais tout mis à jour ou on passerai dès lors une valeur se ferais de manière totalement transparente. Après, ce pose de pourquoi la POO -> paranoïa protectionniste ou clémence envers le mec qui passe derrière toi\ utilise ton code.

    Citation Envoyé par koala01 Voir le message
    Le tout modulo, bien évidemment, le fait que l'objet agisse en réalité comme... une collection
    Question :

    Imaginons deux classes complexes.
    La première, A, n'as, de son point de vue, aucun rapport avec la seconde.
    Quant à la seconde, B, bien qu'elle n'ai pas besoin de A pour fonctionner, elle sait que d'un point de vu externe elle associé à un B (agrégation).
    D'un point de vue externe, on possède des A, des B, et tout fonction de B->A est une surjection.
    (1) Puis-je considérer, selon Demeter, que B agis comme une collection (rajout d'une petite interface supplémentaire peu coûteuse en prévision du respect du SRP); (2)ou suis-je obligé de créer une nouvelle classe multimap (bien plus lourd quand même) ?
    Si deux, êtes vous d'accord pour dire que je n'y gagne n'y en clarté, ni en performance ?

    Citation Envoyé par Emmanuel Deloget Voir le message
    Ce qui est étonnant, c'est qu'on a eu une discussion de 3 pages presque sans aborder ce point qui est pourtant fondamental. Faire le point, ça peut aussi être une bonne manière de faire avancer le débat.

    Dans sa définition, Demeter étant une loi de style, il semblerait qu'on puisse l'appliquer partout. Ce n'est évidemment pas le cas, à moins de recourir à des artifices plutôt... artificiels. Demeter nécessite donc de faire des choix d'architecture logicielle qui vont amener à son application naturelle. En gros : ce n'est pas l'application de la loi de Demeter qui rendra le code meilleur, c'est le fait qu'on puisse l'utiliser et qu'on le fasse qui nous intéresse vraiment.
    Donc en gros, bien que Demeter se dise loi de style, elle devrait se dire corolaire de loi d'architecture ?

    Citation Envoyé par Emmanuel Deloget Voir le message
    * toutes les données sont privées. Pas protected. Pas public. Privées.
    Quelle est le problème, au juste, d'une interface particulière, n'ayant aucune méthode publique / protéger (a part le destructeur en public et constructeur en protégé), aucune donnée publique, mais qui possède un lot de donnée protéger. Sont but alors étant un constructeur complexe -> tu me donne des infos en entrées, je te ressort plein de données en sortie.

    Citation Envoyé par Emmanuel Deloget Voir le message
    La règle de "pas de référence circulaire au niveau des classes" a autant de sens qu'au niveau du package. En fait, c'est un corolaire du principe d'inversion de dépendance - si une référence circulaire existe, alors l'inversion de dépendance n'est pas possible - et une conséquence directe du principe de responsabilité - si la classe A dépends de B, alors B est une responsabilité de A. Si B dépends aussi de A, alors A est une responsabilité de B. Si les deux conditions sont réunies, ni B ni A ne peuvent avoir d'autre responsabilité selon le principe de responsabilité unique, et logiquement, le code ne fait rien. Pas d'une utilité fameuse tout ça...

    Ce n'est pas tout. Les références circulaires sont aussi préjudiciables à l'application du principe ouvert/fermé - dans le sens ou il devient difficile voire impossible d'étendre du code sans modifier le code existant dès lors que ce qu'on souhaite étendre s'auto-référence.

    Trois des principaux principes de conception objet qui sont malmenés sur les 5 les plus utiles, je trouve que c'est un bon chiffre qui nécessite qu'on s'attarde un peu à ce point particulier
    J'ai pas bien compris tout ça, notamment sur ce qu'en pratique une référence circulaire. Un truc comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class A;
    class B {
       A plop();
    }
    class A{
       B b;
       .....
    }
     
    A B::plop() {...}
    ?


    Citation Envoyé par Emmanuel Deloget Voir le message
    setPosition() est un accesseur, tandis que moveTo() est bel et bien un traitement. Dans les faits, les deux font la même chose, pourtant l'un a du sens, l'autre pas tellement. L'abstraction apportée par le nom moveTo() est plus intéressante au point de vue architecture que celle apportée par setPosition(). J'accepte donc moveTo(), mais pas setPosition().
    Existe-t-il des normes de nommage ?
    Si non,
    C'est ton jugement personnel, ta convention de nommage, etc... Enfin bref, c'est un point de vue, compréhensible et partagé (avec moi aussi d'ailleurs). Mais ça reste qu'un point de vue...

    Si oui,
    Quelles sont les textes exactes et ou puis-je les trouver ?

    Et surtout, principale abus, le but de Demeter c'est de maintenir une clarté (utilisation et maintenance). Donc en gros, on jette du flou pour que la clarté soit plus facilement maintenable... C'est un peu comme ne pas se doucher pour pas qu'on puisse dire qu'on est sale en temps normal. C'est vrai, m'enfin Oo quoi !

  9. #49
    Expert confirmé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2007
    Messages
    1 895
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Septembre 2007
    Messages : 1 895
    Points : 4 551
    Points
    4 551
    Par défaut
    Citation Envoyé par JolyLoic Voir le message
    Comment mets-tu en place un concept conteneur/itérateur (avec validation des bornes) sans référence circulaire ?
    L'itérateur possède un constructeur privé qui lui permet d'avoir l'ensemble des références dont il a besoin pour effectuer sa tâche. Exemple pour un tableau et un itérateur bidirectionnel (la même chose peut être appliquée à tous les itérateurs):
    bidi_iterator(T* origin, T* pos, T* end);
    Ainsi, pas besoin de faire référence au conteneur.

    Citation Envoyé par JolyLoic Voir le message
    Ou encore, dans une gestion de graphe avec nœuds et liens, soit un nœud connait ses liens, et un lien connait ses nœuds, soit aucun ne connait les autres, cette connaissance étant centralisée au niveau du graphe lui même. Le design sans référence circulaire est-il meilleur ? Il oblige chaque fonction devant manipuler des liens ou ds nœuds à avoir un paramètre de type graphe. Pour ôter une dépendance circulaire, on a ajouté une dépendance au graphe à plein d'endroit où elle est a priori inutile.
    Pourtant, ne pas avoir de dépendance circulaire dans ce cas a un intérêt fort : une arête peut être dirigée au non, on peut lui associer un coût, ... Il y a de nombreux types d'arrêtes, chacun avec leur comportement propre. Les noeuds peuvent avoir différentes contraintes associées (cardinalité, ...). Mettons que j'ai 3 liens de type différents et 2 noeud de types diférents. Sans référence circulaire, j'ai 5 classes à écrire. Avec des références circulaires, le nombre de classes que je dois écrire explose, et puisque les traitements associés à chaque classe va être différent, il y a de grande chance que ça ait un impact fort dans la classe de gestion du graphe.

    Bien évidemment, le design d'un graphe "ouvert" n'est pas trivial et apparaît beaucouip plus complexe qu'à première vue. Mais ça se saurait si notre métier était trivial...

    Citation Envoyé par JolyLoic Voir le message
    Non, honnêtement, ces arguments, j'ai du mal à y adhérer.
    C'est l'idéal. Il est évident que l'idéal, ça n'est pas toujours la bonne solution. Certains problèmes sont correctement traités en passant par une référence circulaire. Cependant, d'exéprience, ça n'arrive quand même pas très souvent - dans la plupart des cas il existe des solutions élégantes pour casser la référence circulaire. Si la solution nécessaire n'est pas élégante et que le design montre clairement qu'il y a nécessairement une réféence circulaire (cas de l'oeuf et de la poule), alors bien évidemment, il faudra bien en passer par là.

    Citation Envoyé par JolyLoic Voir le message
    Et oui, le principe ouvert/fermé, par exemple, n'a pas de sens pour moi au niveau d'un nœud ou d'un lien. C'est au niveau de l'ensemble du module graphe (avec ses classes graphe, nœud, lien) que je vois l'intérêt de l'appliquer. Ces classes sont trop intriquées pour évoluer indépendamment, et ça ne me choque pas du tout. Là où ça me choquerait, c'est par exemple si je ne pouvais pas les faire évoluer sans modifier tous les clients du graphe, ou si je ne pouvais pas faire évoluer ces clients sans devoir modifier aussi le graphe. Il n'y a pas pour moi de relation client/fournisseur entre ces classes, elles font partie d'un package unique vendu sous blister.
    C'est du bon sens. OCP ne peut pas s'appliquer partout, sans quoi on se retrouve avec une librairie de code générique qui ne fait rien, et le design en est complexifié d'autant. OCP s'applique de manière stratégique - il faut sélectionner les parties qu'on souhaite ouvrir ; le reste est censé ne plus être modifié, sachant que des modifications peuvent quand même intervenir.

    L'exemple du graph est mal choisi pour ça : il est évident qu'il représente un ensemble (conteneur) et n'a aucune raison d'évoluer pour permettre son utilisation. Si il est mathématiquement complet et sans bug, il sera figé dans le marbre. Son implémentation est donc plus ou moins libre, à condition qu'un certain nombre de critères soient respectés. Ceci dit, un package peut êter étendu de la même manière qu'un autre projet. De nouvelles fonctionnalités peuvent être offertes. Si il est possible d'ajouter ses fonctionnalités sans pour autant avoir besoin de modifier le code existant, c'est quand même tout bénéfice, non ?

  10. #50
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    L'itérateur possède un constructeur privé qui lui permet d'avoir l'ensemble des références dont il a besoin pour effectuer sa tâche. Exemple pour un tableau et un itérateur bidirectionnel (la même chose peut être appliquée à tous les itérateurs):
    bidi_iterator(T* origin, T* pos, T* end);
    Ainsi, pas besoin de faire référence au conteneur.
    L'iterateur a des references vers l'implementation du conteneur. Entre ca et une reference au conteneur, je ne vois pas de difference importante. Et s'il y en a une, c'est dans le sens de l'augmentation du couplage: si l'iterateur avait une reference au conteneur, on pourrait peut-etre abstraire une partie de l'implementation dont maintenant il doit avoir connaissance.

    Pourtant, ne pas avoir de dépendance circulaire dans ce cas a un intérêt fort
    Je suis d'accord que qu'il peut y avoir un interet, pas qu'il est necessairement present et encore moins que les complications que cette absence introduit sont plus que compensees par l'interet.

    (On touche ici a un probleme de fond que j'ai avec beaucoup de discussions sur la conception. La conception est pour moi une affaire de compromis entre des criteres contradictoires et ces compromis ne sont au final justifiables que par des considerations sur les circonstances particulieres. Si on oublie cela, on va bien souvent prendre un critere qui en lui-meme est louable, mais en pousser les consequences jusqu'a l'absurde parce qu'on oublie que d'autres criteres poussent dans un autre sens. Il faut s'appuyer sur les principes, ils finissent toujours par craquer.)

    C'est l'idéal. Il est évident que l'idéal, ça n'est pas toujours la bonne solution. Certains problèmes sont correctement traités en passant par une référence circulaire. Cependant, d'exéprience, ça n'arrive quand même pas très souvent - dans la plupart des cas il existe des solutions élégantes pour casser la référence circulaire.
    Nos experiences different. Casser la circularite (entre des types definis dans des packages differents), j'ai du le faire un certain nombre de fois en Ada, ca m'a semble souvent artificiel. Et je ne devais pas etre le seul a qui ca semblait trop souvent trop artificiel, l'iteration suivante de la normalisation d'Ada a introduit un mecanisme pour traiter ce genre de choses.


    Pour revenir sur le premier exemple, casser la circularite change souvent des dependances explicites en dependances implicites. Et ces dernieres sont d'experience sources de plus de problemes que les dependances explicites: on decouvre trop souvent trop tard qu'elles sont impactees par une modification (dans cas du conteneur et l'iterateur, les deux sont tellement lies que l'aspect implicite ou explicite de la reference a peu d'effets de ce point de vue, et on peut meme avoir des raisons de preferer de l'implicites, voir N2913).

  11. #51
    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
    Points : 16 213
    Points
    16 213
    Par défaut
    Citation Envoyé par Emmanuel Deloget Voir le message
    L'itérateur possède un constructeur privé qui lui permet d'avoir l'ensemble des références dont il a besoin pour effectuer sa tâche. Exemple pour un tableau et un itérateur bidirectionnel (la même chose peut être appliquée à tous les itérateurs):
    bidi_iterator(T* origin, T* pos, T* end);
    Ainsi, pas besoin de faire référence au conteneur.
    Comment gères-tu le changement de taille du conteneur après création de l'itérateur ? De plus, ce design augmente l'emprunte mémoire d'un itérateur, qui fait partie des objets qu'on a envie de garder petits.
    Citation Envoyé par Emmanuel Deloget Voir le message
    Pourtant, ne pas avoir de dépendance circulaire dans ce cas a un intérêt fort : une arête peut être dirigée au non, on peut lui associer un coût, ... Il y a de nombreux types d'arrêtes, chacun avec leur comportement propre. Les noeuds peuvent avoir différentes contraintes associées (cardinalité, ...). Mettons que j'ai 3 liens de type différents et 2 noeud de types diférents. Sans référence circulaire, j'ai 5 classes à écrire. Avec des références circulaires, le nombre de classes que je dois écrire explose, et puisque les traitements associés à chaque classe va être différent, il y a de grande chance que ça ait un impact fort dans la classe de gestion du graphe.
    Je ne vois pas trop en quoi. Si on a plusieurs types de nœuds et d'arrêtes, on va certainement extraire un nœud ou arrête abstrait (par classe de base ou par concept), et la dépendance circulaire se fera entre entre ces abstractions, pas entre les classes concrètes. De toute façon, si on ne fait pas ça, et qu'on défère au niveau du graphe la connaissance des relations entre nœuds et arrêtes pour casser la dépendance circulaire, on devra bien écrire 2 classes de nœuds, 3 classes de lien, mais c'est le nombre de classes de graphes qui va lui exploser.

    Citation Envoyé par Emmanuel Deloget Voir le message
    L'exemple du graph est mal choisi pour ça : il est évident qu'il représente un ensemble (conteneur) et n'a aucune raison d'évoluer pour permettre son utilisation. Si il est mathématiquement complet et sans bug, il sera figé dans le marbre. Son implémentation est donc plus ou moins libre, à condition qu'un certain nombre de critères soient respectés. Ceci dit, un package peut êter étendu de la même manière qu'un autre projet. De nouvelles fonctionnalités peuvent être offertes. Si il est possible d'ajouter ses fonctionnalités sans pour autant avoir besoin de modifier le code existant, c'est quand même tout bénéfice, non ?
    Tout à fait, mais je dis juste qu'à mon avis la classe n'est pas le bon niveau d'analyse pour cette réflexion, mais qu'un groupe de classes conçues ensemble et ayant une forte cohésion (pas le niveau bibliothèque, qui lui est trop large, un intermédiaire) me semble plus approprié, même s'il y a des cas, peut-être assez nombreux, où ce groupe se réduit à une classe.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Oui si on renvoie une lvalue (lref ou pointeur); non si on renvoie une rvalue (rref ou valeur). Evidemment, la rref révèle un peu la classe; mais tout mis à jour ou on passerai dès lors une valeur se ferais de manière totalement transparente. Après, ce pose de pourquoi la POO -> paranoïa protectionniste ou clémence envers le mec qui passe derrière toi\ utilise ton code.
    J'aurais tendance à estimer que, si tu renvoies une valeur ou une rvalue reference, tu ne renverra pas un membre de la classe mais un objet créé sur base des membres de ta classe... (ce qui peut parfaitement se justifier )

    Il n'est pas exclu (quoi que discutable) que l'objet renvoyé soit en fait la "copie conforme" d'un membre unique de la classe, mais, dans l'absolu, si tu renvoies une valeur, c'est parce que tu veux renvoyer un objet temporaire créé pour l'occasion au sein de la fonction

    Question :

    Imaginons deux classes complexes.
    La première, A, n'as, de son point de vue, aucun rapport avec la seconde.
    Quant à la seconde, B, bien qu'elle n'ai pas besoin de A pour fonctionner, elle sait que d'un point de vu externe elle associé à un B (agrégation).
    D'un point de vue externe, on possède des A, des B, et tout fonction de B->A est une surjection.
    (1) Puis-je considérer, selon Demeter, que B agis comme une collection (rajout d'une petite interface supplémentaire peu coûteuse en prévision du respect du SRP); (2)ou suis-je obligé de créer une nouvelle classe multimap (bien plus lourd quand même) ?

    Si deux, êtes vous d'accord pour dire que je n'y gagne n'y en clarté, ni en performance ?
    En vertu du principe de la responsabilité unique, je partirais plutôt sur la deuxième solution.

    Et je ne suis pas d'accord pour dire que tu ne gagne ni en clarté ni en performances:

    Tu perdra peut etre un peu en perf du fait de l'indirection supplémentaire, mais, trois classes ayant chacune une interface "aussi restreinte que possible" et leur responsabilité propre seront bien plus claires et faciles à maintenir qu'une classe regroupant l'ensemble des interfaces des trois classes et ayant les trois responsabilités

    Enfin, sous réserve de ne pas modifier (en terme d'argument à passer ou de l'ordre dans lequel le faire) ni supprimer des fonctions de l'interface de A et de B qui sont utilisée par la troisième classe, tu sera en mesure de faire évoluer l'interface des trois classes de manière strictement indépendante et sans devoir t'inquiéter d'aller modifier une fonction particulière de l'une d'elle suite aux changements appliqués dans l'autre
    Donc en gros, bien que Demeter se dise loi de style, elle devrait se dire corolaire de loi d'architecture ?
    Sauf erreur, la loi demeter a, à l'origine, été énoncée pour tout autre chose que l'informatique, mais fortement lié à une méthode de conception cependant...

    Et comme une bonne programmation devrait avant tout s'appuyer sur une bonne conception, il devient difficile de déterminer son domaine réel d'application...

    Ceci dit, elle devrait être prise en compte dés le moment de la conception

    Quelle est le problème, au juste, d'une interface particulière, n'ayant aucune méthode publique / protéger (a part le destructeur en public et constructeur en protégé), aucune donnée publique, mais qui possède un lot de donnée protéger. Sont but alors étant un constructeur complexe -> tu me donne des infos en entrées, je te ressort plein de données en sortie.
    Le raisonnement peut paraitre un peu tordu, mais, le but d'un membre protégé revient à dire
    Je laisse mes descendants s'occuper de cela
    Or, si, l'héritage public aidant, une classe enfant peut "se faire passer pour" sa classe parente, il n'en reste pas moins que la classe enfant subit des restrictions par rapport à sa classe parente, et donc que, bien que l'on parle volontiers de relation "est un" pour l'héritage, que la classe enfant n'est pas "tout à fait" la classe parent

    Par conséquent, il semblerait logique, en vertu de demeter, que même une classe enfant ne puisse accéder aux membres de sa classe parent qu'au travers... des comportements publics et protégés de la classe parent

    Il faut cependant attirer ton attention sur le fait qu'Emmanuel parlait des données membres, et non des fonctions membres (comportements )
    J'ai pas bien compris tout ça, notamment sur ce qu'en pratique une référence circulaire. Un truc comme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class A;
    class B {
       A plop();
    }
    class A{
       B b;
       .....
    }
     
    A B::plop() {...}
    ?
    Ca, ou pire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class A;
    class B
    {
        A* ptrA;
    };
    class A
    {
        B value;
    };
    Existe-t-il des normes de nommage ?
    Si non,
    C'est ton jugement personnel, ta convention de nommage, etc... Enfin bref, c'est un point de vue, compréhensible et partagé (avec moi aussi d'ailleurs). Mais ça reste qu'un point de vue...

    Si oui,
    Quelles sont les textes exactes et ou puis-je les trouver ?
    A ma connaissance, il n'y a pas de regle de nommage uniformisée (portant le label ISO, ANSI ou tout autre)...

    Elles sont généralement relatives à un projet, une équipe ou une entreprise.

    Mais, si j'ai bien compris le raisonnement d'Emmanuel (sans doute parce que j'y adhère), et sans vouloir parler pour lui, lorsque tu utilise le terme "set", cela revient à dire "définis (quelque chose)", alors que, dans l'exemple cité, moveTo induit la notion de mouvement, et introduit donc la notion que j'ai essayé de faire passer plus haut selon laquelle il est possible que cela ne soit pas strictement instantané
    Et surtout, principale abus, le but de Demeter c'est de maintenir une clarté (utilisation et maintenance). Donc en gros, on jette du flou pour que la clarté soit plus facilement maintenable... C'est un peu comme ne pas se doucher pour pas qu'on puisse dire qu'on est sale en temps normal. C'est vrai, m'enfin Oo quoi !
    N'oublie pas la particularité intrinsèque même de tout programme est d'être écrit une fois, lu souvent.

    Or, il n'y a rien à faire: tout comme il devient particulièrement difficile pour tout le monde de retenir quels arguments il faut transmettre et dans quel ordre dés que leur nombre devient plus important que quatre ou cinq (allez, montons même jusqu'à six ou sept, pour les plus doués), il devient rapidement difficile de se rappeler de l'utilisation qui peut être faite d'une classe dés le moment où elle a plus d'une responsabilité ou qu'elle expose plus d'un nombre finalement restreint de fonctions membres...

    Tu as donc "naturellement" intérêt à faire un nombre plus important de petites classe qu'une seule et unique classe qui prendrait en charge l'ensemble des responsabilité de toutes ces petites classes.

    Demeter en "rajoute une couche" en limitant ce que tu dois savoir "du reste" de ton projet afin d'être en mesure d'utiliser n'importe quelle classe prise au hasard.

    Comme souvent en programmation, une chose prise séparément n'a que peu d'impact et d'intérêt, mais trouve tout son intérêt dés qu'elle est mise en relation avec "d'autres choses".

    Demeter ne fait pas vraiment exception en ne s'exprimant pleinement qu'une fois qu'elle est mise en relation avec d'autres lois / règles / principes

  13. #53
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Bon, on dirai que j'ai beaucoup de mal à me faire comprendre... (et malheureusement je penses fort que ça vient de moi :'( ).

    Dans ma question, j'expose deux choix, qui, si j'ai bien compris le SRP (pas dit ça encore). L'un respecte très pour très Demeter (la solution 2); l'autre aussi, mais abuse un peu : je crée une interface EstAssocieAUnA, et considère B (possédant ladite interface) comme une collection de A. D'où l'abus, vu que je n'ai qu'un seul A dans B.

    Pour l'interface à données protégée, en gros, c'est pour le respect du SRP : ma classe avait un constructeur non-trivial, avec de possible évolution futur. Malheureuseument, les données créées étaient tout aussi compliqué à manipuler. Donc j'ai séparé le constructeur dans une classe distincte.
    Bon après, je voyais pas l'intérêt de faire une interface uniquement de getters; d'où mon choix. Cela dit, je conçois très bien qu'une telle classe n'est pas faite pour un héritage public...

    Personnellement, je trouve ça élégant, et je n'y est pas vue de problème. Après, j'ai peut-être mal regarder...

    Pour le reste, je suis plutôt d'accord. Mais ma proposition ne vas pas à l'encontre. En gros je dis que plutôt que d'en faire des éléments totalement distinct, on peux aussi organiser nos interfaces en arbre; avec des getters permettant d'affirmer les connexions existante...
    Certes ce n'est pas la seule solution, mais pourquoi la rejeter ?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Peut être simplement parce qu'il faut penser en termes de services rendus par la classe ou de comportements de la classe plutôt qu'en termes de données utilisées par la classe

    Un accesseur (getter) ou un mutateur (setter) ne donne aucune information sur le service que tu peux attendre de ta classe ni sur le comportement que l'on peut en attendre.

    Ils se contentent, pour l'accesseur, de dire "voilà une des données utilisée" et pour le mutateur "voilà une donnée que tu peux modifier".

    Or tout le paradigme orienté objet est basé sur le fait que l'on doit penser non pas en termes de données, mais bien en termes de comportements, qu'il s'agisse de services que peut rendre une classe ou de messages auxquels la classe peut réagir (de manière interne ou en renvoyant une réponse).

    Ainsi, tout le monde sait parfaitement qu'une voiture dispose d'un réservoir à carburant.

    Mais, à moins d'être mécanicien, le réservoir en tant que tel ne nous intéresse absolument pas: ce qui nous intéresse, c'est l'interface que l'on en a dans la voiture, au travers de la jauge (pour pouvoir "interroger" la voiture sur l'état du réservoir) et de l'orifice de remplicage (pour pouvoir agir sur la quantité de carburant contenue).

    Il ne servirait à rien de demander à la voiture de nous donner accès au réservoir, et encore moins de vouloir le définir: on ne change que très rarement le réservoir sur une voiture (même si je l'ai fait sur la mienne il y a quelques mois à peine )

    Par contre, que la voiture nous donne une interface permettant de connaitre le quotient de la quantité de carburant contenue par la quantité maximale contenable ou exporte la fonction "ajouterCarburant(nombre_de_centilitres) et utilise en interne une autre fonction de l'interface du réservoir "utiliserCarburant(nombre_de_centilitre)", ca, ca nous intéresse au plus haut point:

    Les deux premiers parce qu'il nous permettent d'agir sur le réservoire, la troisième fonction parce qu'elle permet, lorsque la voiture recoit de la part du moteur une information "j'ai utilisé XXX centilitre"de faire en sorte que le réservoir en tienne compte dans l'évaluation de la quantité de carburant restante

    Il existe, effectivement, des cas moins clairs que celui-ci, comme par exemple, ce qui concerne le nom et le prénom d'une personne, car, effectivement, le "service" que l'on attend d'une personne est, entre autres, d'être en mesure de s'identifier... en fournissant son nom et son prénom...

    Mais, dans l'absolu, nous sommes bien plu souvent dans une situation proche de la voiture que dans une situation proche de la personne

  15. #55
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Mon c'est peut-être parce que c'est le matin() et que je suis pas super efficace... mais c'est quoi le rapport avec ce que j'ai dit ?

    Bon, comme je vois un léger lien avec ma "conclusion", je dirai que le but n'est pas d'exposer ces données mais de construire des interface en arbre. En gros, on pourrait faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Interface.getSousInterface().method
    C'est ça l'idée... Et je trouve ça très claire, bien que anti-demeterien...

    Si c'est pour mon constructeur externe, ben ça reviens trait pour trait à faire une classe Constructeur avec une seule méthode qui retournerai mes données voulues... mais en plus optimisé. La aussi pas très demeterien en somme... Mais c'est un truc "super" SRP(de ce que je crois en avoir compris ) => ma classe ne pourra jamais avoir plus de responsabilité que de fournir mes données. Ou alors attention à l'emmêlement neuronal !

    En gros ce que je dit, c'est qu'il y a quand même pas mal de cas où on peut se passer de Demeter (en tant que loi de style), en ayant un code tout aussi claire, et parfois plus performant.

  16. #56
    Membre averti
    Profil pro
    Inscrit en
    Janvier 2007
    Messages
    301
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2007
    Messages : 301
    Points : 345
    Points
    345
    Par défaut
    @Lavock comme le dit koala01, on ne ferait pas voiture.getRéservoir().ajouterCarburant(nombre_de_centilitres) mais directement voiture.ajouterCarburant(nombre_de_centilitres) qui elle appellera m_réservoir.ajouterCarburant(nombre_de_centilitres) (avec m_réservoir un membre privé)

    @koala01
    Et je ne suis pas d'accord pour dire que tu ne gagne ni en clarté ni en performances:
    Si tu as une relation noeud / arc dans un graphe et que pour les raisons citées précédemment, tu t'interdit une des deux relations par exemple tu autorises uniquement la relation noeud -> arc. Si à un moment, tu as besoin à partir d'un arc de connaitre les noeuds accessibles tu vas être obligé d'utiliser une structure de type map<arc*, vector<noeud*>>, donc tu vas forcément perdre en performance entre un accès direct de type monArc.noeuds_accessibles() qui renverrait un membre de type vector<noeud*> et ma_map.find(&monArc)->second non?

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par CedricMocquillon Voir le message
    @Lavock comme le dit koala01, on ne ferait pas voiture.getRéservoir().ajouterCarburant(nombre_de_centilitres) mais directement voiture.ajouterCarburant(nombre_de_centilitres) qui elle appellera m_réservoir.ajouterCarburant(nombre_de_centilitres) (avec m_réservoir un membre privé)
    C'était bien le sens de mon intervention
    @koala01
    Et je ne suis pas d'accord pour dire que tu ne gagne ni en clarté ni en performances:
    Si tu as une relation noeud / arc dans un graphe et que pour les raisons citées précédemment, tu t'interdit une des deux relations par exemple tu autorises uniquement la relation noeud -> arc. Si à un moment, tu as besoin à partir d'un arc de connaitre les noeuds accessibles tu vas être obligé d'utiliser une structure de type map<arc*, vector<noeud*>>, donc tu vas forcément perdre en performance entre un accès direct de type monArc.noeuds_accessibles() qui renverrait un membre de type vector<noeud*> et ma_map.find(&monArc)->second non?
    Tu as coupé ma citation un paragraphe trop tôt (les deux points en fin de phrase l'attestent )

    En effet, le paragraphe suivant était:
    Tu perdra peut etre un peu en perf du fait de l'indirection supplémentaire, mais, trois classes ayant chacune une interface "aussi restreinte que possible" et leur responsabilité propre seront bien plus claires et faciles à maintenir qu'une classe regroupant l'ensemble des interfaces des trois classes et ayant les trois responsabilités
    ce qui rejoint effectivement ce que tu dis

    De plus, j'ai l'habitude de mettre en garde quant à l'éventuel arbitraire des règles, qu'il s'agisse de lois, de principes, de convention ou de n'importe quoi d'autre, et principalement lorsque l'on parle de programmation et ou de conception.

    Si une règle est trop arbitraire, et, de ce fait, contre productive dans un contexte donné, je plaide généralement en faveur du bon sens qui tendrait à ignorer cette règle, à condition d'être sur de savoir ce que l'on fait:

    Eviter le goto ou préférer un algorithme SESE sont des pratiques que je trouve globalement très saines.

    Cependant, dans certains cas, une utilisation raisonnée du goto ou le fait d'avoir plusieurs sorties de fonctions peuvent représenter la "moins mauvaise" solution, qui devrait alors être choisie.

    De même, la récursivité s'avère parfois très intéressante, à condition de ne la mettre en oeuvre que parce qu'elle est, effectivement, utile, et non "simplement" pour faire une figure de style.

    Le respect de demeter est une position globalement saine et de nature à éviter bien des soucis.

    Mais, dans certains cas, il est possible qu'elle soit tout à fait inadaptée.

    Dans ces rares cas, le bon sens devrait nous imposer de choisir la "moins mauvaise" solution et donc de préférer faire une entorse à la règle... A condition de savoir très précisément justifier la raison qui nous a poussé à faire cette entorse et de savoir ce que l'on fait

  18. #58
    Membre confirmé Avatar de Lavock
    Profil pro
    Inscrit en
    Octobre 2009
    Messages
    560
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2009
    Messages : 560
    Points : 633
    Points
    633
    Par défaut
    Citation Envoyé par CedricMocquillon Voir le message
    @Lavock comme le dit koala01, on ne ferait pas voiture.getRéservoir().ajouterCarburant(nombre_de_centilitres) mais directement voiture.ajouterCarburant(nombre_de_centilitres) qui elle appellera m_réservoir.ajouterCarburant(nombre_de_centilitres) (avec m_réservoir un membre privé)
    Question de nomenclature...

    Et voiture.getOrifice().mettreEssence(nbcl) ça vous parrait aussi stupide ? Moi oui, parceque la, l'objet est simple...

    Prenons plus gros... Un avion. A ben c'est balo ça, j'ai plus d'un reservoir ! Bon, ben alors faisons une méthode AjouterEssence(numReservoir,nbLitre)...
    Et mince... non seulement j'ai plusieurs réservoir, mais en plus il ne se remplise pas tous de la même façon... Et on peu aussi en changer de temps en temps ? Aie,aie,aie...
    Avion.getOrifice(num).mettreEssence(). L'avion n'as plus besoin de reveler ou de connaitre même la nature de ses réservoirs pour qu'on puisse le remplir...
    L'avion sais qu'il a des réservoirs -> il va simplement transmettre l'interface qui sera utile à la personne voulant le remplir.

    Le but n'est en rien de faire des accesseur juste pour le fun, mais bel est bien donner accès à de nouvelle méthodes via des portails (getters). Bien sur, généralement c'est du
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    const dataInterface&& getData() {
       return static_cast<dataInterface>(data);
    };
    Mais rappel: cela est interdit par Demeter...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 629
    Points : 30 692
    Points
    30 692
    Par défaut
    Citation Envoyé par Lavock Voir le message
    Question de nomenclature...

    Et voiture.getOrifice().mettreEssence(nbcl) ça vous parrait aussi stupide ? Moi oui, parceque la, l'objet est simple...

    Prenons plus gros... Un avion. A ben c'est balo ça, j'ai plus d'un reservoir ! Bon, ben alors faisons une méthode AjouterEssence(numReservoir,nbLitre)...
    Et mince... non seulement j'ai plusieurs réservoir, mais en plus il ne se remplise pas tous de la même façon... Et on peu aussi en changer de temps en temps ? Aie,aie,aie...
    Avion.getOrifice(num).mettreEssence(). L'avion n'as plus besoin de reveler ou de connaitre même la nature de ses réservoirs pour qu'on puisse le remplir...
    L'avion sais qu'il a des réservoirs -> il va simplement transmettre l'interface qui sera utile à la personne voulant le remplir.
    A ce moment là, tu ne met pas getOrifice, mais plutot selectTank(unsigned int), et tu maintient dans ton avion un pointeur sur le réservoir sélectionné.

    Pour permettre de chainer les appels, tu peux envisager de renvoyer une référence sur... l'avion :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    Avion & Avion::selectTank(unsigned int number)
    {
        if(number>= tanks_.size()) 
            throw BadTankNumber() //évitons de sélectionner le troisieme
                               // réservoir sur un avion qui n'en a que deux :D
        selectedTank_=& tanks_[number];
        return *this;
    }
    Cette fonction et le pointeur associé seront non seulement utiles pour le remplicage, mais également pour le vol, afin de déterminer dans quel réservoir il faut aller "chercher" le carburant, voir, lors de la check-list, afin de vérifier que les réservoirs soient correctement remplis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    /* fonction effectuant la chec-list
     * @ return : 1 go
     *            0 no go
     */
    int checkList(avion & a)
    {
        /* ce qu'il faut vérifier avant les niveaux des réservoir */
        unsigned int resMax=a.tankCount();
        for(unsigned int i=0;i<resMax;++i)
            if(a.selectTank(i).tankLevel()<100) /* 0 reservoir vide / 100 reservoir full */
                return 0;
        /* ce qui doit être fait après */
    }
    Tu n'a, en effet, absolument pas besoin de disposer du réservoir lui-même: tu dois te baser sur les instruments de l'avion

  20. #60
    Expert éminent

    Inscrit en
    Novembre 2005
    Messages
    5 145
    Détails du profil
    Informations forums :
    Inscription : Novembre 2005
    Messages : 5 145
    Points : 6 911
    Points
    6 911
    Par défaut
    Citation Envoyé par koala01 Voir le message
    A ce moment là, tu ne met pas getOrifice, mais plutot selectTank(unsigned int), et tu maintient dans ton avion un pointeur sur le réservoir sélectionné.
    C'est le genre de chose qui me gene (tout comme les iterateurs internes aux conteneurs). Ca empeche de remplir deux reservoirs en parallele par exemple.

    En passant, je vais redire ce que j'ai deja ecrit: les discussions sur une conception sans utilisation bien definie sont artificielles, on peut avoir des arguments pour tout et n'importe quoi et on n'a aucun moyen de juger des compromis. Hors la conception est un art du compromis.

Discussions similaires

  1. Que pensez-vous des générateurs de doc PHP ?
    Par Nonothehobbit dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 64
    Dernier message: 10/07/2007, 10h17
  2. Que pensez vous de filemaker
    Par thpopeye dans le forum Autres SGBD
    Réponses: 4
    Dernier message: 14/06/2007, 15h20
  3. Que pensez vous du nouveau kernel 2.6 ?
    Par GLDavid dans le forum Administration système
    Réponses: 58
    Dernier message: 02/08/2004, 15h45
  4. [Débat] Que pensez-vous des langages à typage dynamique?
    Par Eusebius dans le forum Langages de programmation
    Réponses: 14
    Dernier message: 16/06/2004, 12h12
  5. Que pensez vous du mariage ASP Flash?
    Par tyma dans le forum Flash
    Réponses: 4
    Dernier message: 09/07/2003, 15h00

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