{{tag>cours dev poo pharo mooc}} ====== Le paradigme orienté objet ====== Tutoriel [[000_start|Programmation objet immersive en Pharo]] proposé par l'**inria** disponible à l'adresse https://mooc.pharo.org et sur la plateforme FUN-MOOC. ===== Transcription de la vidéo ===== Présentation par Stéphane Ducasse, direction de recherche, Inria. Dans ce cours, je vous montrerai que la programmation objet et la conception objet représentent le monde d'une manière décentralisée. ==== Différentes façons de représenter le monde ==== D'abord, il faut voir qu'il n'y a pas un modèle central et unique du monde. Si on compare la notion de risque dans une banque et dans une assurance, on pourrait croire que c'est la même chose, pourtant c'est un peu différent. Pour l'assurance, la notion de risque, c'est son business intégral, alors que pour la banque, le risque est juste que vous ne remboursiez pas, donc ils prennent quelques précautions liées à ce risque spécifique. Comme on peut le percevoir ici, on va avoir différents modèles pour modéliser une même chose. Maintenant, il y a différentes façons d'aborder la modélisation et de créer ces modèles. Dans le passé, des approches étaient dirigées par les données, d'autres étaient plus favorables aux bases de données relationnelles. Il y a eu de la programmation objet, ce qu'on étudie dans ce cours, de la programmation procédurale et d'autres. ==== L'approche orienté objet ==== L'**approche orientée objet**, qu'est-ce que c'est? C'est un **paradigme**. Ce n'est pas une technologie. C'est une **façon** différente de simuler et **de représenter le monde** pour l'exploiter selon ses objectifs. L'idée, c'est d'organiser cette modélisation du monde avec une **représentation d'organisation décentralisée**. L'idée, à ce moment-là, c'est d'essayer de **contrôler la complexité** de ces systèmes et de permettre leur **meilleure réutilisation**. ==== Comparaison avec une approche procédurale ==== D'abord, on va faire une comparaison entre une modélisation procédurale et une modélisation objet. Si on regarde la modélisation procédurale, elle va faire un focus sur les données et les procédures. * Les données sont partagées entre toutes les procédures. * Les données sont accessibles par tous les clients et les procédures connaissent toutes les structures des données. Il n'y a pas cette distance qu'il y a entre un message et une méthode comme dans la modélisation objet. Il n'y a pas de notion de liaison tardive. Donc, ça veut dire qu'on a besoin d'un grand nombre de procédures. Il n'y a pas la possibilité d'avoir deux procédures qui ont le même nom et qui auraient des comportements différents, comme on l'a vu dans la programmation objet lors des cours précédents. Prenons un exemple. Si on modélise une image ou un diagramme qui serait composé de formes géométriques comprenant un rectangle, un carré et un cercle et admettons que je veuille calculer l'aire de ce diagramme. Dans une vision procédurale du monde, je vais définir une procédure que je peux appeler 'pictureArea' et dans cette procédure, que vais-je faire? Je vais parcourir la liste des formes géométriques qui composent le diagramme et à chaque fois, je vais regarder la donnée. Je vais dire : * Si c'est un carré, je vais faire côté multiplié par côté; * Si c'est un rectangle, je vais faire longueur multipliée par largeur; * Si c'est un cercle, je vais calculer pi r²; * etc. Au final je retournerai le résultat: la somme de ces aires. **Quel est le désavantage de cette approche**? Il y en a plusieurs. Le premier, c'est que la **définition est monolithique**. Elle n'est pas embêtante en elle-même, mais ses implications le sont. Ça signifie que je ne peux pas la réutiliser. Je ne peux pas réutiliser la fonction 'pictureArea' si j'ajoute une nouvelle forme. Si demain, je mets une étoile dedans, je vais devoir modifier le code de 'pictureArea'. En plus, je ne peux pas réutiliser la définition de l'aire dans un carré ou un rectangle, puisque **tout est défini au même endroit**. Le **modèle objet**, d'un autre côté, est complètement différent. Il **va déléguer** le calcul de l'aire à d'autres entités. Donc, la classe Diagramme, Picture, que va-t-elle faire? Elle va juste faire une boucle sur chacune des formes géométriques et demander à chaque forme géométrique de calculer son aire. Chaque forme géométrique va définir une méthode aire qui va lui retourner la bonne définition. Quel est l'avantage? Déjà, je peux ajouter une forme géométrique sans aucun problème. Il suffit juste que j'ajoute une classe avec le message aire et que je crée les objets de cette classe. Je peux réutiliser la méthode aire de la classe Picture. Donc, là, j'ai vraiment de la réutilisation. On voit qu'on a un **calcul décentralisé**. Ça signifie que la classe Diagramme va demander aux autres classes de faire un calcul pour elle. Si on regarde, il y a vraiment un point central. C'est que si même dans la vision objet, j'avais défini des méthodes avec des noms différents, je n'aurais pas pu avoir le bénéfice entier de l'approche objet. Ce qui est important, c'est que chacune des formes géométriques se met d'accord et **offre la même interface au client**. Ça signifie que chacune des formes va offrir la méthode aire, ce qui va permettre au client de ne pas avoir à faire de distinction et du coup, qu'on puisse le réutiliser. Ça s'appelle **le polymorphisme**. Différents objets vont pouvoir répondre à un même message avec différentes exécutions. Ça, c'est tout d'un coup très puissant. ==== La POO ou programmation orientée objet ==== Donc, qu'est-ce qu'une application dans un système objet ? * C'est un ensemble d'entités (les objets) qui vont collaborer et interagir. * Les objets ont un **comportement** et un **état**. * Que cet **état est privé** et n'est **accessible que des méthodes**. * Ces objets interagissent avec des messages et que ces messages sont résolus dynamiquement et que la méthode correspondante va être exécutée lors de l'exécution. Et le dernier point que j'ai mentionné, c'est que ces messages forment souvent des familles polymorphiques qui me permettront de réutiliser le code. Donc, les messages, je le disais, ont une entité unique. Le point central, c'est qu'ils doivent exposer des interfaces polymorphiques qui seront substituées par d'autres objets. Maintenant, j'aimerais aborder trois points essentiels de la programmation objet qui sont les pierres angulaires de la programmation objet. ==== L'encapsulation ==== La première, c'est **l'encapsulation**. On l'a vue dans un autre cours. C'est l'idée qu'en tant que client, je vais envoyer un message à un objet et l'objet contrôle la manière dont il encode l'information et la manière dont il va faire du calcul. Cette encapsulation est vraiment importante, car je pourrai substituer un objet par un autre sans que le client soit impacté et c'est très important, car ça va **favoriser la réutilisation**. Cette **encapsulation va permettre**, par exemple, une **composition d'objets**. En tant que client, qu'un objet fasse tout le calcul ou qu'il distribue son calcul à d'autres objets, ça ne m'importune pas à partir du moment où je ne sais pas que ça se passe et que je ne suis pas impacté par les décisions de cet objet. Donc, **l'encapsulation et la composition d'objets vont de pair**. La composition d'objets va permettre l'explicitation d'un calcul souvent de manière plus simple. ==== Décentralisation ==== L'autre pierre angulaire, c'est cette **notion de distribution** ou de décentralisation. L'idée, c'est que quand je vais calculer quelque chose, ça va être le résultat de plusieurs objets qui exécutent des sous-tâches. C'est **favorisé par la liaison tardive** qui va dire, en fait : "Je saurai quelle est la méthode à exécuter lors de l'exécution et ce sera basé sur la classe du receveur." C'est **renforcé par cette notion de polymorphisme** qui va faire que plusieurs objets vont pouvoir être substituables et proposer la même interface. Donc, cet ensemble de points va favoriser cette idée qu'on aura un système qui sera plus décentralisé et qui va pouvoir maximiser de la réutilisation. Dans l'exemple qu'on avait pris avec le diagramme, le comportement du calcul de l'aire du diagramme est indépendant du calcul de l'aire de chacun de ces éléments. Donc, on le réutilise. ==== Héritage ==== Le dernier point-clé de la programmation objet que je ne montre pas dans ce cours mais que je veux évoquer, c'est l'idée que je pourrai définir des abstractions par extension d'autres abstractions. Imaginons qu'on ait une classe qui représente des collections. Je pourrai définir une autre classe, qui est une OrderedCollection, par extension de la collection. Je pourrai définir la classe Tableau par extension de la classe Collection. Par extension, je vais réutiliser tous les comportements que j'ai définis dans la classe Collection et je pourrai spécialiser ces comportements dans chaque classe. Donc, l'**héritage est ce mécanisme qui permet une définition incrémentale d'une abstraction par rapport à une autre**. Et c'est très important dans la programmation objet. Dans le cadre de ce cours, je le traite après, mais je voulais dire que c'est vraiment un point essentiel. ==== Conclusion ==== Finalement, qu'a-t-on vu? On a vu que dans une conception objet: * Un programme, c'est des entités qui collaborent et envoient des messages; * Que les objets, ces entités encapsulent les données et contrôlent l'interface qu'elles exposent à leurs clients. * La liaison tardive permet de sélectionner la bonne méthode à exécuter et va éviter à un client de devoir faire des vérifications avant d'exécuter un message. Et ce mécanisme-là est renforcé si les objets qui offrent un même service le décrivent par des méthodes qui ont le même nom, ce qui va faire que le client va pouvoir simplement donner les ordres sans avoir à devoir choisir quel ordre il doit donner pour chaque objet avec lequel il interagit. * Les Classes réutilisent et étendent le comportement de leur classe parente via le mécanisme d'héritage. * Qu'une bonne conception objet favorise le polymorphisme