La programmation orientée objet ( POO ) est un paradigme de programmation basé sur les objets – des entités logicielles qui encapsulent des données et une ou plusieurs fonctions . programme informatique POO est constitué d'objets qui interagissent entre eux. Un langage POO est un langage qui offre des fonctionnalités de programmation orientée objet, mais comme l'ensemble des fonctionnalités qui contribuent à la POO est sujet à débat, la classification d'un langage comme POO – et le degré de prise en charge de la POO qu'il offre – est discutable. Les paradigmes n'étant pas mutuellement exclusifs, un langage peut être multiparadigme (c'est-à-dire catégorisé comme appartenant à plusieurs paradigmes). Parmi les langages notables prenant en charge la POO, on peut citer Ada , ActionScript , C++ , Common Lisp , C# , Dart , Eiffel , Fortran 2003 , Haxe , Java , JavaScript , Kotlin , Logo , MATLAB , Objective-C , Object Pascal , Perl , PHP , Python , R , Raku , Ruby , Scala , SIMSCRIPT , Simula , Smalltalk , Swift , Vala et Visual Basic (.NET) .
Parallèlement, en Norvège, Simula a été développé entre 1961 et 1967. Simula a introduit des concepts essentiels de la programmation orientée objet, tels que les classes , l'héritage et la liaison dynamique . Simula était principalement utilisé par les chercheurs travaillant sur la modélisation physique , notamment le mouvement des navires et de leur cargaison dans les ports de marchandises. Simula est généralement considéré comme le premier langage possédant les caractéristiques et le cadre fondamentaux d'un langage orienté objet.
J'imaginais les objets comme des cellules biologiques et/ou des ordinateurs individuels sur un réseau, capables de communiquer uniquement par messages (la messagerie est donc apparue dès le début – il a fallu un certain temps pour trouver comment implémenter la messagerie dans un langage de programmation de manière suffisamment efficace pour être utile).
Influencé par le MIT et Simula, Alan Kay commença à développer ses propres idées en novembre 1966. Il créera par la suite Smalltalk , un langage de programmation orientée objet (POO) influent. Dès 1967, Kay utilisait couramment le terme « programmation orientée objet » . Bien que parfois considéré comme le « père » de la POO Kay a déclaré que ses idées différaient de la compréhension commune de la POO et a laissé entendre que la communauté informatique n'avait pas adopté sa conception . Une note du MIT de 1976, co-écrite par Barbara Liskov, cite Simula 67 , CLU et Alphard parmi les langages orientés objet, mais ne mentionne pas Smalltalk
Dans les années 1970, la première version du langage de programmation Smalltalk a été développée au Xerox PARC par Alan Kay , Dan Ingalls et Adele Goldberg . Smalltalk-72 se distinguait par son utilisation d'objets au niveau du langage et par son environnement de développement graphique. Smalltalk était un système entièrement dynamique, permettant aux utilisateurs de créer et de modifier des classes en temps réel. Une grande partie de la théorie de la programmation orientée objet (POO) a été développée dans le contexte de Smalltalk, notamment l'héritage multiple.
À la fin des années 1970 et dans les années 1980, la programmation orientée objet (POO) a pris de l'importance. Le Lisp orienté objet Flavors a été développé à partir de 1979, introduisant l'héritage multiple et les mixins . En août 1981, le magazine Byte a mis en lumière Smalltalk et la POO, faisant ainsi connaître ces concepts à un large public. LOOPS, le système d'objets d' Interlisp -D, a été influencé par Smalltalk et Flavors, et un article à son sujet a été publié en 1982. En 1986, la première conférence sur la programmation orientée objet, les systèmes, les langages et les applications ( OOPSLA ) a réuni 1 000 participants. Cette conférence a marqué le début des efforts de consolidation des systèmes d'objets Lisp, aboutissant finalement au Common Lisp Object System . Dans les années 1980, quelques tentatives de conception d'architectures de processeurs intégrant la gestion matérielle des objets en mémoire ont été menées , mais sans succès. Les exemples incluent l' Intel iAPX 432 et le Linn Smart Rekursiv .
Au milieu des années 1980, de nouveaux langages orientés objet comme Objective-C , C++ et le langage Eiffel ont fait leur apparition. Objective-C a été développé par Brad Cox , qui avait utilisé Smalltalk chez ITT Inc. Bjarne Stroustrup a créé C++ en s'appuyant sur son expérience avec Simula pour sa thèse de doctorat. Bertrand Meyer a conçu la première version du langage Eiffel en 1985, axée sur la qualité logicielle grâce à une approche de conception par contrat .
Dans les années 1990, la programmation orientée objet (POO) est devenue la principale méthode de programmation, notamment grâce à la prise en charge croissante de cette approche par des langages tels que Visual FoxPro 3.0 , C++ et Delphi . La POO a gagné en popularité avec l'essor des interfaces graphiques , qui utilisent des objets pour les boutons, les menus et autres éléments. Le framework Cocoa d'Apple , utilisé sur macOS et écrit en Objective-C , en est un exemple bien connu . Les boîtes à outils de POO ont également contribué à populariser la programmation événementielle .l'ETH de Zurich , Niklaus Wirth et ses collègues ont créé de nouvelles approches de la programmation orientée objet (POO). Modula-2 (1978) et Oberon (1987) proposaient une approche originale de l'orientation objet, des classes et de la vérification des types entre modules. L'héritage n'est pas évident dans la conception de Wirth, car sa nomenclature est inversée : on parle d'extension de type, et le point de vue va du parent à l'héritier.
De nombreux langages de programmation initialement développés avant que la POO ne soit populaire ont été enrichis de fonctionnalités orientées objet, notamment Ada , BASIC , Fortran , Pascal et COBOL .
Caractéristiques
la programmation relationnelle , est difficile car il n'existe pas de définition claire et consensuelle de la POO.
Encapsulation et masquage de l'information
Les termes « dissimulation » et « encapsulation » peuvent désigner plusieurs concepts connexes :
- La cohésion consiste à regrouper les champs et les méthodes liés . Un champ (ou attribut, ou propriété) contient des informations (ou un état) sous forme de variable . Une méthode (ou fonction , ou action) définit un comportement via du code logique.
- Le découplage consiste à organiser le code de sorte que seules certaines parties des données soient utilisées par les fonctions associées. Le découplage facilite la modification du fonctionnement interne d'un objet sans affecter d'autres parties du code , comme lors d'une refactorisation . Les objets font office de frontière entre leur fonctionnement interne et le code externe qui les utilise.
- Le masquage des données consiste à dissimuler les détails internes d'un objet au code extérieur. Grâce aux modificateurs d'accès fournis par le langage, le code utilisateur ne peut interagir avec un objet que par l'intermédiaire de ses membres publics, contrôlant ainsi leur visibilité.
Certains langages de programmation, comme Java, permettent de masquer les informations via des mots clés de visibilité (`private` Eric S. Raymond a écrit que les langages POO tendent à encourager des programmes à forte structure en couches qui nuisent à la transparence. Raymond compare défavorablement cette approche à celle adoptée avec Unix et le langage C.
SOLID inclut le principe ouvert/fermé , selon lequel les classes et les fonctions doivent être « ouvertes à l’extension, mais fermées à la modification ». Luca Cardelli a déclaré que les langages orientés objet ont des « propriétés de modularité extrêmement faibles en ce qui concerne l’extension et la modification des classes » et ont tendance à être extrêmement complexes. Ce dernier point est réitéré par Joe Armstrong , le principal inventeur d’ Erlang , qui aurait déclaré :
Le problème des langages orientés objet, c'est qu'ils traînent avec eux tout un environnement implicite. Vous vouliez une banane, mais vous vous êtes retrouvé avec un gorille tenant la banane et toute la jungle.
Leo Brodie affirme que la dissimulation d'informations peut conduire à du code dupliqué , ce qui va à l'encontre de la règle « ne vous répétez pas » du développement logiciel.
Héritage
L'héritage peut être pris en charge via la classe ou le prototype , qui présentent des différences mais utilisent des termes similaires comme objet et instance .
Basé sur les classes
En programmation orientée objet ( POO), le type le plus courant, un objet est une instance d'une classe. La classe définit les données (variables) et les méthodes (logique). Un objet est créé via le constructeur . Chaque instance de la classe possède le même ensemble de variables et de méthodes. Les éléments peuvent inclure :
- Variable de classe – appartient à la classe elle-même ; tous les objets de la classe partagent une seule copie.
- Variable d'instance – appartient à un objet ; chaque objet possède sa propre version de ces variables.
- Variable membre – désigne à la fois les variables de classe et les variables d'instance d'une classe
- Méthode de classe – ne peut utiliser que des variables de classe
- Méthode d'instance – appartient à un objet ; peut utiliser des variables d'instance et de classe
Les classes peuvent hériter d'autres classes, créant ainsi une hiérarchie : une sous-classe héritant d'une super-classe. Par exemple, une l'héritage multiple , où une classe peut hériter de plusieurs classes, et d'autres prennent en charge les mixins ou les traits . Par exemple, un mixin appelé UnicodeConversionMixin peut ajouter une méthode unicode_to_ascii() aux classes FileReader et WebPageScraper.
Une classe abstraite ne peut pas être instanciée directement en tant qu'objet. Elle est uniquement utilisée comme super-classe.
D'autres classes sont des classes utilitaires qui ne contiennent que des variables et des méthodes de classe et ne sont pas destinées à être instanciées ou sous-classées.
Basé sur un prototype
Au lieu de proposer un concept de classe, la programmation par prototypes associe un objet à un autre objet, appelé son prototype ou parent . En `Self`, un objet peut avoir plusieurs parents ou aucun , mais en JavaScript , le langage par prototypes le plus répandu, un objet possède exactement un lien de prototype, jusqu'à l'objet de base dont le prototype est nul.
Un prototype sert de modèle pour les nouveaux objets. Par exemple, si vous avez un objet A la composition d'objets , un objet peut contenir d'autres objets. Par exemple, un Go , ne prennent pas en charge l'héritage . Ils privilégient plutôt la « composition », où les objets sont construits à partir de composants plus petits au lieu de relations parent-enfant. Par exemple, au lieu d'hériter de la classe Person, la classe Employee pourrait simplement contenir un objet Person. Cela permet à la classe Employee de contrôler la quantité d'objets Person qu'elle expose aux autres parties du programme. La délégation est une autre fonctionnalité du langage qui peut être utilisée comme alternative à l'héritage.
Les programmeurs ont des opinions divergentes sur l'héritage. Bjarne Stroustrup, auteur du C++, a affirmé qu'il était possible de faire de la programmation orientée objet sans héritage. Rob Pike a critiqué l'héritage, le jugeant responsable de la création de hiérarchies complexes au lieu de solutions plus simples.
Hérédité et sous-typage comportemental
On pense souvent que si une classe hérite d'une autre, la sous-classe est une version plus spécifique de la classe d'origine. Cela suppose que, dans la sémantique du programme , les objets de la sous-classe peuvent toujours remplacer sans problème les objets de la classe d'origine. Ce concept est connu sous le nom de sous-typage comportemental , et plus précisément sous le nom de principe de substitution de Liskov .
Cependant, cela est souvent faux, notamment dans les langages de programmation autorisant les objets mutables , c'est-à-dire des objets qui changent après leur création. En effet, le polymorphisme de sous-type, tel qu'appliqué par le vérificateur de types dans les langages orientés objet, ne garantit pas un sous-typage comportemental dans la plupart, voire la totalité, des contextes. Par exemple, le problème du cercle et de l'ellipse est notoirement difficile à résoudre avec le concept d'héritage de la programmation orientée objet. Le sous-typage comportemental étant généralement indécidable, il est difficilement implémentable par un compilateur. De ce fait, les programmeurs doivent concevoir avec soin les hiérarchies de classes afin d'éviter les erreurs que le langage de programmation lui-même ne peut détecter.
répartition dynamique
Une méthode peut être appelée par dispatch dynamique, de sorte qu'elle soit sélectionnée à l'exécution et non à la compilation. Si le choix de la méthode dépend de plusieurs types d'objets (par exemple, d'autres objets passés en paramètres), on parle de dispatch multiple . Dans ce contexte, un appel de méthode est également appelé passage de message : le nom de la méthode et ses entrées sont comme un message envoyé à l'objet pour qu'il l'exécute.
La répartition dynamique fonctionne de concert avec l'héritage : si un objet ne possède pas la méthode demandée, il se réfère à sa classe parente ( délégation ) et remonte la chaîne pour trouver une méthode correspondante.
Polymorphisme
Le polymorphisme en POO fait référence au sous-typage ou au polymorphisme de sous-type, où une fonction peut fonctionner avec une interface spécifique et ainsi manipuler des entités de classes différentes de manière uniforme.
Par exemple, imaginons un programme comportant deux formes : un cercle et un carré. Toutes deux appartiennent à une classe commune appelée « Forme ». Chaque forme possède sa propre méthode de dessin. Grâce au polymorphisme de sous-type, le programme n’a pas besoin de connaître le type de chaque forme et peut simplement appeler la méthode « Dessiner » pour chacune d’elles. L’environnement d’exécution du langage de programmation se chargera d’exécuter la version appropriée de la méthode « Dessiner » pour chaque forme. Le fait que les détails de chaque forme soient gérés au sein de leurs propres classes simplifie le code et le rend plus organisé, permettant ainsi une séparation efficace des responsabilités .
Récursivité ouverte
Les méthodes d'un objet peuvent accéder à ses données. De nombreux langages de programmation utilisent un mot-clé, comme `this` la récursivité ouverte , une méthode d'un objet peut appeler d'autres méthodes du même objet, y compris elle-même, grâce à ce mot-clé. Cela permet à une méthode d'une classe d'appeler une autre méthode définie ultérieurement dans une sous-classe ; cette fonctionnalité est appelée liaison tardive .
Modèles de conception
Les patrons de conception sont des solutions courantes aux problèmes de conception logicielle. Certains patrons de conception sont particulièrement utiles pour la programmation orientée objet (POO) et sont généralement introduits dans ce contexte.
Modélisation et relations dans le monde réel
Parfois, les objets représentent des éléments et des processus du monde réel sous forme numérique. Par exemple, un logiciel graphique peut comporter des objets tels que Niklaus Wirth a déclaré : « Ce paradigme [la POO] reflète fidèlement la structure des systèmes du monde réel et est donc bien adapté à la modélisation de systèmes complexes présentant un comportement complexe. »
Cependant, le plus souvent, les objets représentent des entités abstraites, comme un fichier ouvert ou un convertisseur d'unités. L'idée que la programmation orientée objet (POO) facilite la reproduction exacte du monde réel, voire même sa nécessité, ne fait pas l'unanimité. Bob Martin suggère que, les classes étant des logiciels, leurs relations ne correspondent pas aux relations du monde réel qu'elles représentent. Bertrand Meyer soutient qu'un programme n'est pas un modèle du monde, mais un modèle d'une partie du monde : « La réalité est une cousine éloignée. » Steve Yegge a constaté que les langages naturels ne suivent pas l'approche POO consistant à nommer une chose (objet) avant une action (méthode), contrairement à la programmation fonctionnelle qui procède inversement. Cela peut rendre une solution POO plus complexe qu'une solution écrite par programmation procédurale .
Modèles d'objets
Voici quelques modèles de conception logicielle notables pour les objets OOP.
- Objet fonction : Classe avec une méthode principale qui se comporte comme une fonction anonyme (en C++, l'opérateur de fonction
Objet immuable : ne change pas d'état après sa création - Objet de première classe : peut être utilisé sans restriction
- Objet conteneur : contient d'autres objets
- Objet Factory : crée d'autres objets
- Métaobjet : Utilisé pour créer d'autres objets (similaire à une classe , mais un objet).
- Objet prototype : un méta-objet spécialisé qui crée de nouveaux objets en se copiant lui-même
- Objet singleton : unique instance de sa classe pendant toute la durée de vie du programme
- Objet filtre : reçoit un flux de données en entrée et le transforme en sortie de l'objet
Un anti-modèle courant est celui de l' objet divin , un objet qui en sait ou en fait trop.
Modèles de conception du Gang des Quatre
Ces solutions, appelées « modèles de conception », sont regroupées en trois types :
- Modèles de création (5) : Modèle de méthode de fabrique , Modèle de fabrique abstraite , Modèle Singleton , Modèle de constructeur , Modèle Prototype
- Motifs structuraux (7) : Motif adaptateur , Motif pont , Motif composite , Motif décorateur , Motif façade , Motif poids plume , Motif proxy
- Modèles de comportement (11) : Modèle de chaîne de responsabilités , Modèle de commande , Modèle d’interpréteur , Modèle d’itérateur , Modèle de médiateur , Modèle de mémoire , Modèle d’observateur , Modèle d’état , Modèle de stratégie , Modèle de méthode de modèle , Modèle de visiteur
Orientation objet et bases de données
Pour résoudre ce problème, les développeurs utilisent différentes méthodes, mais aucune n'est parfaite. L'une des solutions les plus courantes est le mappage objet-relationnel (ORM), qui permet de connecter les programmes orientés objet aux bases de données relationnelles. Parmi les outils ORM, on peut citer Visual FoxPro , Java Data Objects et ActiveRecord de Ruby on Rails .
Certaines bases de données, dites bases de données orientées objet , sont conçues pour fonctionner avec la programmation orientée objet. Cependant, elles n'ont pas connu le même succès que les bases de données relationnelles.
Date et Darwen ont proposé une base théorique qui utilise la POO comme une sorte de système de types personnalisable pour prendre en charge les SGBDR, mais elle interdit les objets contenant des pointeurs vers d'autres objets.
Conception axée sur la responsabilité vs. conception axée sur les données
Dans la conception axée sur les responsabilités , les classes sont construites en fonction de leurs besoins et des informations qu'elles partagent, sous la forme d'un contrat. Cela diffère de la conception axée sur les données , où les classes sont construites en fonction des données qu'elles doivent stocker. Selon Wirfs-Brock et Wilkerson, les initiateurs de la conception axée sur les responsabilités, cette dernière est la meilleure approche.
directives SOLID et GRASP
SOLID est un ensemble de cinq règles pour concevoir de bons logiciels, créé par Michael Feathers :
- Principe de responsabilité unique : Une classe ne devrait avoir qu'une seule raison de changer.
- Principe ouvert/fermé : Les entités logicielles doivent être ouvertes à l'extension, mais fermées à la modification.
- Principe de substitution de Liskov : Les fonctions qui utilisent des pointeurs ou des références à des classes de base doivent pouvoir utiliser des objets de classes dérivées sans le savoir.
- Principe de ségrégation des interfaces : les clients ne doivent pas être contraints de dépendre d’interfaces qu’ils n’utilisent pas.
- Principe d'inversion des dépendances : Dépendre des abstractions, et non des éléments concrets.
GRASP (General Responsibility Assignment Software Patterns) est un autre ensemble de règles de conception logicielle, créé par Craig Larman , qui aide les développeurs à attribuer des responsabilités à différentes parties d'un programme :
- Principe du créateur : permet aux classes de créer des objets qu’elles utilisent fréquemment.
- Principe de l'expert en information : attribue des tâches aux classes disposant des informations nécessaires.
- Principe de faible couplage : réduit les dépendances entre les classes pour améliorer la flexibilité et la maintenabilité.
- Principe de forte cohésion : concevoir des classes avec une responsabilité unique et ciblée.
- Principe du contrôleur : attribue les opérations système à des classes distinctes qui gèrent le flux et les interactions.
- Polymorphisme : permet d’utiliser différentes classes via une interface commune, favorisant ainsi la flexibilité et la réutilisation.
- Principe de Pure Fabrication : créer des classes d’assistance pour améliorer la conception, renforcer la cohésion et réduire le couplage.
sémantique formelle
Les chercheurs ont tenté de définir formellement la sémantique de la programmation orientée objet (POO). L'héritage présente des difficultés, notamment en raison des interactions entre la récursivité ouverte et l'état encapsulé. Les chercheurs ont utilisé des types récursifs et des types de données co-algébriques pour intégrer des caractéristiques essentielles de la POO. Abadi et Cardelli ont défini plusieurs extensions du système F qui traitent des objets mutables, permettant à la fois le polymorphisme de sous-type et le polymorphisme paramétrique (génériques), et ont pu modéliser formellement de nombreux concepts et constructions de la POO. Bien que loin d'être triviale, l'analyse statique des langages de programmation orientés objet tels que Java est un domaine mature, disposant de plusieurs outils commerciaux.