La programmation orientée objet (POO) est un style de programmation dans lequel les logiciels sont construits sur la base de classes et d’objets. La programmation orientée objet étant aujourd’hui la forme la plus répandue de développement de logiciels, même les programmeurs novices devraient connaître cette approche et en avoir compris les caractéristiques de base. C’est pourquoi, dans cet article, nous allons aborder la définition de la programmation orientée objet, ses principaux composants et concepts, ainsi que ses avantages et inconvénients.
Qu’est-ce que la programmation orientée objet ?
La programmation orientée objet fait partie des paradigmes de programmation impérative. Un paradigme fait simplement référence à une approche particulière de la programmation. Si les paradigmes impératifs impliquent que le développeur spécifie les étapes du déroulement du programme, il existe également des paradigmes déclaratifs où seul le résultat est décrit, et non le chemin pour y parvenir.
Globalement, il existe deux grands paradigmes impératifs : le paradigme procédural et le paradigme orienté objet. Dans la programmation procédurale, le code est constitué de sous-routines et de fonctions (regroupées sous le nom de procédures) qui sont utilisées pour contrôler le programme. L’orientation objet, quant à elle, utilise des classes et des objets. Les objets ont un état défini par des attributs ou des propriétés et fournissent des méthodes qui contiennent une logique commerciale.
Un aspect important qui est souvent oublié dans la définition de la POO est la nécessité pour les objets d’encapsuler leur état et de communiquer entre eux uniquement par l’envoi et la réception de messages.
Brève histoire de la programmation orientée objet
L’idée d’objets en termes de programmation orientée objet est apparue pour la première fois au MIT à la fin des années 1950 – le terme faisait alors référence à des entités identifiables dotées d’attributs. Les premiers langages à mettre en œuvre cette approche ont été Simula 67 et Smalltalk. En particulier, Smalltalk et son développeur Alan Key ont eu un impact durable sur le développement de la programmation orientée objet. Dans Smalltalk, toutes les parties du logiciel – même les classes, les messages ou les magasins de données – sont des objets, ce qui renforce fortement le paradigme.
L’orientation objet a connu une percée majeure avec le C++, le perfectionnement du langage procédural C, dans les années 1980. Depuis les années 1990, de nombreux autres langages de programmation orientés objet, aujourd’hui populaires, ont été ajoutés, tels que Java et C#. La plupart des langages modernes supportent désormais à la fois les paradigmes orientés objet et procédural, ou des mélanges des deux.
Termes de la programmation orientée objet
Entrons maintenant dans la théorie de la programmation orientée objet. Pour ce faire, définissons d’abord les termes les plus importants, tels qu’objet et classe, puis examinons de plus près certains concepts de base.
Objets et méthodes
Un objet est un élément qui possède un état interne basé sur des propriétés ou des attributs et des méthodes. Les méthodes agissent sur les valeurs concrètes des propriétés et modifient ainsi l’état de l’objet. Ils servent également d’interface à d’autres objets par lesquels des messages peuvent être envoyés et reçus. L’objet décide toujours lui-même de la manière dont il traite les messages et modifie ses données. Par conséquent, il se trouve dans un état bien défini et autocontrôlé. Les objets disposent généralement de méthodes permettant de les créer et, le cas échéant, de les détruire. Ces méthodes sont appelées respectivement constructeur et destructeur.
Une méthode a une signature qui spécifie les valeurs d’entrée qu’elle attend et la valeur de retour qu’elle a. Dans de nombreux langages, vous pouvez également préciser quelles autres classes peuvent accéder à la méthode. C’est ce qu’on appelle la visibilité de la méthode. Une distinction est faite entre
Les méthodes publiques, auxquelles toutes les autres classes peuvent accéder.
Les méthodes protégées, qui ne sont visibles que par les classes elles-mêmes et les classes dérivées. Nous allons expliquer ce qu’est exactement une classe dérivée dans un instant.
Les méthodes privées du paquet, qui peuvent être vues par les classes du même paquet. Pour cela, le langage de programmation doit prendre en charge les paquets ou les espaces de noms, comme c’est le cas avec Java, par exemple.
Les méthodes privées, qui ne peuvent être appelées que par la classe qui implémente la méthode. Cela est nécessaire, par exemple, pour diviser une longue méthode en sous-programmes courts sans rendre les routines individuelles accessibles à d’autres objets.
Classes
Le concept de classes est utilisé pour gérer des objets similaires. Les classes servent de modèles sur la base desquels des objets concrets peuvent être créés au moment de l’exécution. Un objet est donc une instance d’une classe. Il peut y avoir un nombre quelconque d’instances indépendantes d’une classe. Dans sa fonction de modèle, une classe définit à la fois des attributs et des méthodes et décrit ainsi le comportement de toutes ses instances.
À titre d’exemple, considérons une classe Personne. Chaque personne a un prénom, un nom de famille et un âge. Il peut également effectuer certaines activités, comme manger ou boire. Une personne concrète possède des valeurs pour ces attributs, par exemple, le nom Max, et l’âge de 38 ans, ou le nom Michel et l’âge de 23 ans. Tous deux possèdent non seulement ces attributs, mais peuvent également manger et boire parce qu’ils sont des personnes.
Identité de l’objet
Un aspect important des objets est qu’ils sont identifiables indépendamment de leurs propriétés. C’est ce qu’on appelle l’identité d’objet, qui signifie que l’objet reste le même, même si son état change, tout comme une personne reste la même après avoir changé de nom ou d’adresse. Cela signifie que l’objet n’a pas besoin de révéler toutes ses propriétés ou son état interne pour être adressable de manière unique.
Concepts importants du développement logiciel orienté objet
Maintenant que nous avons clarifié ce que sont exactement les classes et les objets, replaçons-les dans leur contexte en examinant de plus près certains concepts importants du développement logiciel orienté objet. Il s’agit de l’héritage, des classes abstraites, des interfaces et du polymorphisme. Nous aborderons ensuite certains des principes du développement logiciel orienté objet, en particulier l’encapsulation des données et le principe de responsabilité unique.
Héritage
L’héritage est un élément central du développement de logiciels orientés objet. Une relation d’héritage existe toujours entre deux classes et est hiérarchique. Une classe est la classe de base (super classe) et une autre est la classe dérivée (sous classe). La classe dérivée hérite de tous les attributs et fonctions de la superclasse. Il peut ajouter de nouveaux attributs et fonctions ou remplacer ceux qui existent par sa propre mise en œuvre. Cela s’appelle l’écrasement.
L’héritage présente l’avantage de pouvoir étendre une classe existante sans avoir à la modifier par la suite. En outre, les sous-classes peuvent être utilisées dans le code à la place de leur super-classe car elles possèdent toutes les interfaces de la super-classe.
Qu’est-ce que cela signifie exactement ?
Considérez les appareils électriques de votre foyer : ils ont tous des fonctions extrêmement différentes : La bouilloire chauffe l’eau, tandis que la lampe fournit de la lumière. Mais les deux ont une interface commune, à savoir la fiche. Le fait que la prise alimente une bouilloire ou une lampe ne fait absolument aucune différence.
Nous pourrions donc combiner ces dispositifs dans une classe de base ElectricalDevice avec une fiche et une interface connect(). Les classes WaterBoiler et Lamp héritent de cette classe.
Un socket mettrait alors en œuvre une méthode plug_in() qui prendrait simplement un dispositif électrique comme paramètre et appellerait la méthode connect() sur celui-ci. Si un nouvel appareil électrique, tel qu’un mixeur, est ajouté à la cuisine, cela n’a pas d’importance pour la prise ; elle peut raccorder le mixeur de la même manière.
Polymorphisme
L’exemple des appareils de cuisine illustre un autre concept de l’orientation objet, le polymorphisme. Le polymorphisme vient du grec et signifie quelque chose comme la multiformité. On parle de polymorphisme lorsque la signature d’une méthode est la même pour différentes classes, mais qu’elle est mise en œuvre différemment. C’est le cas dans notre exemple pour la méthode turn_on() : Celle-ci n’a aucune logique pour la classe abstraite, mais chaque appareil électrique implémente son propre comportement. Le polymorphisme présente l’avantage que le code peut être réutilisé à de nombreux endroits en même temps et qu’il peut être utilisé et étendu de manière flexible.
Masquage d’informations
Un aspect important à prendre en compte lors de la conception des classes est l’encapsulation des données, ou le masquage des informations. Chaque objet devrait avoir le contrôle exclusif de ses données, les cacher et ne les rendre accessibles à l’extérieur que par le biais d’une interface. Les autres classes ne doivent pas savoir à quoi ressemble exactement le code à l’intérieur d’une autre classe, et ne doivent pas non plus faire de suppositions à ce sujet.
Séparation des préoccupations / Principe de responsabilité unique
La séparation des préoccupations ou principe de responsabilité unique fait référence à la répartition claire des responsabilités au sein d’un système logiciel. Chaque classe doit représenter exactement une responsabilité et être fortement cohésive et indépendante des autres classes (couplage lâche). Ce n’est qu’à ce moment-là que les objets et les classes peuvent cacher leurs caractéristiques internes et être échangés ou étendus à volonté. Comme le masquage d’informations, le principe de responsabilité unique n’est pas imposé par les langages orientés objet, mais il doit être pris en compte lors de la conception du logiciel.
Avantages et inconvénients de la programmation orientée objet
L’orientation objet présente de nombreux avantages, sinon elle ne serait pas le paradigme dominant du développement logiciel moderne. L’un des principaux avantages est l’encapsulation de la logique et des données dans des classes individuelles. Cela améliore la maintenabilité et rend le code plus facile à étendre. Les différentes parties du logiciel ou d’un flux de travail peuvent être remplacées et le système global est flexible. Les hiérarchies d’héritage favorisent également la réutilisation du code et évitent ainsi la redondance. Enfin, il y a l’amélioration de la testabilité et donc de la robustesse du logiciel – chaque classe peut être considérée séparément et testée indépendamment des autres parties du système global.
Cependant, la programmation orientée objet présente également certains inconvénients. Bien que la pensée en termes d’objets soit relativement proche du mode de pensée naturel des humains, le flux de contrôle du code est parfois plus difficile à suivre. Un autre inconvénient est que les objets ne peuvent souvent pas être mis en correspondance directement avec les bases de données relationnelles – les concepts les plus importants tels que l’identité, l’état, le comportement et l’encapsulation n’existent pas ici. Ce problème est souvent décrit comme une inadéquation de l’impédance objet-relationnel. Enfin, une orientation objet trop poussée peut entraîner une dégradation du temps d’exécution. Pour cette raison, les approches orientées objet et procédurales sont souvent mélangées dans la pratique.