Les Programmations Orientées Objet

La Programmation Orienté Objet (POO pour les intimes) est de nos jours la lingua franca de la programmation dite impérative. Pourtant, fort est de constater que celle couramment usitée est loin de l’approche définie par son auteur, Alan Kay, au point que l’on peut dire qu’il existe actuellement en fait deux approches orientées objet !

En quoi les deux approches diffèrent elles ? On pourrait résumer cette différence par ceci :

  • dans l’approche la plus pratiquée, l’accent du développement est mis sur la structuration des objets avec une volonté d’encapsuler leur état. Débutant avec Simula 67, elle est de nos jours commune et véhiculée par des langages comme C++ ou Java.
  • dans l’approche originale, l’accent est au contraire mis sur le comportement des objets, caractérisé par l’ensemble des messages qu’ils comprennent, la structure de ceux-ci et leur changement d’état étant encapsulé ; la structuration est reléguée au second rang. Initiée avec Smalltalk, elle est véhiculée de nos jours par des langages comme Smalltalk, Io ou Ruby.

D’où vient cette différence ? Une explication peut être donnée avec ces propos d’Alan Kay :

The “official” computer science world started to regard Simula as a possible vehicle for defining abstract data types (even by one of its inventors), and it formed much of the later backbone of ADA. […] Instead, the objects should be presented as site of higher level behaviors more appropriate for use as dynamic components.

A l’origine, les concepteurs de Smalltalk et pères de la POO se sont inspirés des techniques utilisées dans d’autres langages (Lisp, Sketchpad, JOSS, …) pour implémenter les concepts sous-jacents à la POO, et parmi ceux-là les constructions utilisées dans Simula les ont fortement inspirés. A cette époque, on travaillait sur un moyen de structurer le code à l’aide de types abstraits de données. C’est dans ce contexte que certains, comme Ole-Johan Dahl et Kristen Nygaard, les auteurs de Simula, ne virent de la POO que comme une meilleure structuration du code à l’aide de constructions idoines : classes de données, instanciation, sous-typage, attachement dynamique (ces deux derniers permettant le polymorphisme), etc. C’est sous cette tendance qu’ont émergés d’autres langages comme Pascal Object ou C++ qui, à leur tour, ont influencé plusieurs générations de développeurs. C’est ainsi que, pour beaucoup, la POO se résume à écrire des structures (les classes) regroupant à la fois les champs (appelés attributs) et les opérations (appelées méthodes), dont l’interface (les parties accessibles depuis l’extérieur) forme le type ; cette approche est plutôt une programmation orientée classe dans laquelle la classe fusionne le concept de module avec celui de type.

Pour mieux comprendre les concepts sous-jacents à la POO et ce qu’avaient en tête son auteur, je recommande fortement la lecture de l’histoire de Smalltalk. On peut y lire, entre autre, que la POO est née de plusieurs idées, dont l’une d’elle peut être résumée par ces propos de Bob Barton :

The basic principal of recursive design is to make the parts have the same power as the whole.

Et dans leur vision, les objets sont perçus comme des cellules d’un organisme cellulaire ou des petits ordinateurs dans un réseau par le biais duquel ils interagissent par messages.

Plus concrètement, dans cet échange de mails, Alan Kay expliquent ce qu’est la POO :

OOP to me means only messaging, local retention and protection and hiding of state-process, and extreme late-binding of all things.

Alan Kay ne parle aucunement de structuration. Il met en avant d’abord les concepts de messages, puis d‘encapuslation à la fois des effets de bords et des détails techniques et d’implémentation, et de … résolution retardée ! L’expression extreme late-binding of all things peut surprendre mais est essentielle pour plusieurs choses dont le polymorphisme. Pour comprendre ceci, il faut d’abord savoir qu’en POO le concept de message est décoléré de celui de méthode : une méthode est la réponse propre à l’objet à un message donné (autrement dit son code d’implémentation). Ensuite, tout objet qui sait répondre à un message, quelque soit son type, doit pouvoir être utilisé comme receveur. Donc, la méthode à exécuter en réponse à un message ne peut être connue que lorsque le type réel de l’objet est identifié, ce qui ne peut se faire que tardivement, c’est-à-dire lorsque celui-ci est effectivement inféré (le message est transmis à l’objet). Ceci permet à un objet dont le type satisfait l’interface attendue d’être utilisé en tant que receveur et ceci sans nécessairement entrer dans une relation de sous-typage avec l’interface ; celle-ci peut d’ailleurs être dynamique au sens où elle définit uniquement les messages attendus dans un contexte donné. On dit alors que le type de l’objet est un élément de la classe de types représentée par cette interface ; autrement dit il satisfait l’interface définie par la classe de types. En effet, en POO, le polymorphisme provient d’un typage d’ordre supérieur et des relations de sous-classement (les classes ici en tant qu’ensembles polymorphiques de types, cf. le Polymorphisme F-Bound de William Cook et al. ou les articles de Anthony J.H. Simons sur la théorie de la classification dans le JOT, Journal Of Object Technology) ; les relations entre objets ne reposent plus sur le type des objets mais sur l’appartenance de leur type à des classes de types. (Ce que les développeurs Ruby appellent, in vulgare sermo, le duke typing.) Les langages comme C++, Java ou C#, quant à eux, ont rejeté le concept de message, et réalisent le polymorphisme par des relations de sous-typage (principe de Liskov) et par la surcharge de méthodes, mais celui-ci offre des possibilités en deçà de celui de la POO ; c’est pourquoi, pour étendre les possibilités polymorphiques, ils permettent, via la généricité, et dans une certaine mesure, un typage de second ordre (quantification universelle ou, mieux, contrainte). Voici un exemple de type de second ordre contraint en Java :

public class Persistable<T extends Persistable<T>> {
  ...
}

Je conclurai brièvement cette article avec cette phrase du GOOS (Growing Object-Oriented Software) :

Your domain model is not in the classes you create in your source code, but in the messages that the objects pass to one another when they communicate at runtime.

Miguel Moquillon

Author: Miguel Moquillon

Restez au courant de l'actualité et abonnez-vous au Flux RSS de cette catégorie

Commentaires (0)

Les commentaires sont fermés


Aucune annexe



À voir également

L'extensibilité d'objets métiers dans différents langages

Il arrive fréquemment qu’avec l’évolution des besoins dans le temps, les objets métiers qui ont été définis auparavant nécessitent d’être étendu par l’ajout de nouvelles fonctionnalités. Selon la nature des langages de programmation, mais aussi selon les caractéristiques propres aux langages, les méthodes d’extensions varient et peuvent être plus ou moins aisées à mettre en œuvre, en particulier lorsque les extensions sont fournies dans des modules (paquetages, bibliothèques, …) à part et que l’existant ne doit pas être impacté par ces ajouts (ou du moins le minimum possible). Dans ce petit billet je voudrais vous présenter certaines d’entre elles, et en particulier dans le contexte présenté ci-dessus, et ceci avec trois langages de programmations différents : Java, un langage impératif (orienté classe), Smalltalk, un des rares langages qui soient vraiment orienté objet, et Haskell, un langage fonctionnel.

Lire la suite

Foncteurs, Foncteurs Applicatifs et Monades

Dans ce premier billet de l’année 2018, je vais m’essayer de vous présenter ce que sont les foncteurs, les foncteurs applicatifs et les monades de façon simple, sans étalage de la théorie mathématique derrière (celle des catégories) dont, de toute manière, je ne maîtrise pas. Bien que ce soient des constructions utilisées dans la programmation fonctionnelle, elles peuvent aussi être utilisées dans d’autres approches de programmation et avec d’autres langages que ceux fonctionnels. C’est pourquoi je présenterai chacun des concepts non seulement avec du code en Haskell mais aussi en Java.

Lire la suite