Partage
  • Partager sur Facebook
  • Partager sur Twitter

Bonnes pratiques en POO

Sujet résolu
    19 septembre 2017 à 5:14:37

    Bonjour à tous ! Mon problème concerne un objet complexe qui serait composé de sous-objets relativement complexes eux aussi :

    Si on imagine par exemple une classe Joueur qui dispose d'une Arme. Le joueur vient d'acheter une lunette de précision pour son fusil, qu'on souhaite donc ajouter à l'arme qu'il porte. Une solution simple serait de faire quelque chose comme :

    joueur.getArme().ajouterLunette(lunette)

    Mais dans ce cas-là, on modifie l'arme au travers d'un getter, ce qui n'est pas très propre.

    Une autre solution consisterait à faire une méthode ajouterLunetteSurArme(lunette) à la classe Joueur, mais dans ce cas-là ça duplique du code (puisque cette méthode ne contiendrait qu'un appel à la méthode ajouterLunette de la classe Arme), et on finirait par se retrouver avec toutes les méthodes de la classe Arme réécrites dans la classe Joueur, ce qui n'est pas génial non plus...

    Du coup, quelle est la solution à privilégier ?


    J'ai également une 2e question, et je vais profiter de ce topic pour la poster ici :

    Si j'ai bien compris, certains considèrent les getters et setters comme une mauvaise pratique, mais une pratique moins mauvaise que de rendre un attribut public. Le problème serait que ces getters et setters vont à l'encontre de la programmation orientée objet. Celle-ci consiste à créer une entité (une classe) avec des données, et fournir au développeur une interface pour utiliser cette entité. Dans cette logique, il n'est pas cohérent de permettre au développeur de définir la vie d'un joueur ("setHealth(value)") mais il faudrait lui permettre de blesser le joueur (lui faire perdre de la vie) ou le guérir (lui en faire gagner), voire reset sa santé (et encore, c'est déjà limite...).

    Ma question est assez simple : ai-je bien compris leur point de vue ? Serait-il préférable d'écrire des fonctions assez haut niveau afin d'abstraire complètement le fonctionnement de l'objet manipulé, même si on connaît cet objet (car on l'a codé) et que dans certains cas, avoir une fonction qui permet de modifier la vie du joueur aussi bien de manière positive que négative peut s'avérer intéressant ?


    Je vous remercie par avance pour vos réponses :)

    • Partager sur Facebook
    • Partager sur Twitter
      19 septembre 2017 à 9:02:41

      Lu'!

      Greak a écrit:

      Du coup, quelle est la solution à privilégier ?

      Il n'y a pas duplication de code dans le second cas, ce n'est qu'une délégation, et c'est très commun en programmation. Par contre, la question qu'on peut fortement se poser, c'est "pourquoi il y a besoin de faire ça de l'extérieur de joueur ?". Après tout, il serait bien plus cohérent que ces éléments soient dans l'inventaire du joueur et que ce soit cette entité qui se démerde avec son fatras en interne. On peut se poser une question encore plus importante :

      Est ce que toute ces considérations ont vraiment un sens d'un point de vue programmatique ?

      Et de ce côté la réponse est très probablement : non. La lunette (ou autre machin), c'est qu'un modifieur pour les caractéristiques (et éventuellement capacités) de base de l'arme associée à une représentation graphique particulière : la lunette. Donc plutôt que d'avoir des classes dédiées pour cela, autant avoir la notion de "Modifieur" qui aura les impacts voulus sur les caractéristiques, et après que ce soit une lunette, un chargeur, une crosse ou autre, OSEF : ce sera que des questions graphiques. D'un point de vue programmation ça n'aura aucun impact donc pas besoin de différencier.

      Greak a écrit:

      Celle-ci consiste à créer une entité (une classe) avec des données, et fournir au développeur une interface pour utiliser cette entité.

      Non. C'est l'inverse. C'est précisément ça qui est important. Une classe définit une interface de manipulation et pour l'implémentation de cette interface, on lui associe des données. La première question que l'on doit se poser en objet, c'est "qu'est ce que je veux faire avec ?" et on ne doit surtout pas penser aux données internes avant d'avoir défini ce qu'on veut faire. Notamment parce que basiquement, on doit pouvoir changer toutes les données internes pour une autre implémentation sans que cela n'impacte le code utilisateur.

      Les getters/setters sur les attributs d'un objet ne sont qu'un symptôme du fait que l'on n'a pas raisonné dans le bon sens, c'est pas la cause d'une conception foireuse, juste un signal d'alarme. Parfois les getters (voir même les setters) peuvent faire du sens : s'ils représentent un service et pas une modification pure et simple du contenu de l'objet.

      • Partager sur Facebook
      • Partager sur Twitter

      Posez vos questions ou discutez informatique, sur le Discord NaN | Tuto : Preuve de programmes C

        19 septembre 2017 à 17:33:47

        Si tu cherches des conseils de bonnes pratiques en programmation (objet ou non) il y a zen of python ('import this" à chercher sur internet)

        Tu peux aussi te renseigner sur les design pattern. Pour ce qui est de ton problème, lorsque tu en arrives à te poser des questions comme celles là c'est que tu as un problème de conception de tes objets. Dans ce genre de cas il vaut mieux prendre une feuille et un crayon pour lister ce qui va et ce qui ne va pas dans le code. Parfois au moment de choisir entre deux façon de faire on choisi une mauvaise solution et ça abouti à un problème bien plus tard dont on a du mal à déterminer la cause. Pour ce qui est de la POO il y a un conseil qu'il ne faut pas oublier : un objet hérite souvent un comportement d'une interface. (l'exemple ci dessous est bidon car ton problème vient sans doute d'une conception mais utiliser une méthode de classe pour appeler la même méthode avec un objet interne ça n'a rien de mauvais à condition d'avoir une bonne conception). 

        public Interface IDecorateurArme {
        
            void Decorer(string type_elem);
        
        }
        
        public class Arme extends IDecorateurArme {
           
            void Decorer(string type_elem) {
                // ...
            }
        
        }
        
        public class Personnage extends IDecorateurArme {
        
            private Arme arme;
        
            void Decorer(string type_elem) {
                this.arme.Decorer(type_elem);
            }
        
        }
        • Partager sur Facebook
        • Partager sur Twitter
          20 septembre 2017 à 1:05:24

          Ok, merci à tous les 2. J'y vois plus clair.

          Je pense en effet que le problème se situe essentiellement au niveau de la conception. J'avais cette question en tête depuis un moment et quand je regarde aujourd'hui ce que j'ai fait il y a 1 an, je me dis que je ne re-ferai pas les choses de la même manière.

          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            21 septembre 2017 à 17:40:08

            La POO c'est quelque chose de technique, tu n'aurais pas assez d'un bouquin de 800 pages pour en expliquer les tenants et les aboutissants.

            Par contre le bon sens, tu dois l'avoir un minimum... Quand tu dis par exemple ajouter un objet comme une lunette sur une arme d'un de tes joueurs, ça veut dire que ton arme a la possibilité d'être composé de divers petits objets. Ensuite, le fait d'ajouter un objet à un joueur, sans savoir s'il sera utile ou non à d'autres objets, ça reste un ajout d'objet. À toi de vérifier par la suite que les objets se complémentent ou non.

            Pour ta question, j'ajoute une lunette donc un objet à joueur, c'est simple !

            joueur.ajoute(obj)

            Après ton mode de pensée diffère de celui de quelqu'un d'autre, ta logique n'est pas la même, mais il doit y avoir un fil conducteur.

            Bref, la POO c'est améliorer l'organisation de son code lié à un langage en utilisant des techniques diverses, par contre, ce qui fait que tu as une logique, c'est juste ta façon ou ta manière de penser les divers objets.

            • Partager sur Facebook
            • Partager sur Twitter

            Bonnes pratiques en POO

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown