La programmation orientée objet (POO), ou programmation par objet, est un paradigme de programmation informatique. Elle consiste en la définition et l'interaction de briques logicielles appelées objets ; un objet représente un concept, une idée ou toute entité du monde physique, comme une voiture, une personne ou encore une page d'un livre. Il possède une structure interne et un comportement, et il interagit avec ses pairs. Il s'agit donc de représenter ces objets et leurs relations ; l'interaction entre les objets via leurs relations permet de concevoir et réaliser les fonctionnalités attendues, de mieux résoudre le ou les problèmes. Dès lors, l'étape de modélisation revêt une importance majeure et nécessaire pour la POO. C'est elle qui permet de transcrire les éléments du réel sous forme virtuelle.

La programmation par objet consiste à utiliser des techniques de programmation pour mettre en œuvre une conception basée sur les objets. Celle-ci peut être élaborée en utilisant des méthodologies de développement logiciel objet, dont la plus connue est le processus unifié (« » en anglais), et exprimée à l'aide de langages de modélisation tels que le Unified Modeling Language (UML).

La programmation orientée objet est facilitée par un ensemble de techniques dédiées :

les langages de programmation : Ada, AS3, C++, Common Lisp, C#, Dart, Eiffel, Fortran, Haxe, Java, JavaScript, Kotlin, LOGO, Lua, Matlab, Objective-C, Object Pascal, Perl, PHP, Python, R, Raku, Ruby, Scala, Simula, Smalltalk, Swift, Vala, VB.NET ; les outils de modélisation qui permettent de concevoir sous forme de schémas semi-formels la structure d'un programme (, UMLDraw., Rhapsody, DBDesigner…) ; les bus distribués (DCOM, CORBA, RMI, Pyro…) ; les ateliers de génie logiciel ou AGL (Visual Studio pour des langages Dotnet, NetBeans ou Eclipse pour le langage Java).

Il existe actuellement deux grandes catégories de langages à objets : les langages à classes, que ceux-ci soient sous forme fonctionnelle (Common Lisp Object System), impérative (C++, Java) ou les deux (Python, OCaml) ; les langages à prototypes (JavaScript, Lua).

Origines En implantant les Record Class de Hoare, le langage Simula 67 pose les constructions qui seront celles des langages orientés objet à classes : classe, polymorphisme, héritage, etc. Mais c'est réellement par et avec Smalltalk 71 puis Smalltalk 80, inspiré en grande partie par Simula 67 et Lisp, que les principes de la programmation par objets, résultat des travaux d'Alan Kay, sont véhiculés : objet, encapsulation, messages, typage et polymorphisme (via la sous-classification) ; les autres principes, comme l'héritage, sont soit dérivés de ceux-ci ou une implantation. Dans Smalltalk, tout est objet, même les classes. Il est aussi plus qu'un langage à objets, c'est un environnement graphique interactif complet.

À partir des années 1980, commence l'effervescence des langages à objets : C++ (1983), Objective-C (1984), Eiffel (1986), Common Lisp Object System (1988), etc. Les années 1990 voient l'âge d'or de l'extension de la programmation par objets dans les différents secteurs du développement logiciel.

Depuis, la programmation par objets n'a cessé d'évoluer aussi bien dans son aspect théorique que pratique et différents métiers et discours mercatiques à son sujet ont vu le jour : l'analyse objet (AOO ou OOA en anglais) ; la conception objet (COO ou OOD en anglais) ; les bases de données objet (SGBDOO) ; les langages objets avec les langages à prototypes ; ou encore la méthodologie avec Model driven architecture (MDA). Aujourd'hui, la programmation par objets est vue davantage comme un paradigme, le paradigme objet, que comme une simple technique de programmation. C'est pourquoi, lorsque l'on parle de nos jours de programmation par objets, on désigne avant tout la partie codage d'un modèle à objets obtenu par AOO et COO.

Principes

La programmation orientée objet a été introduite au milieu des années 1960 par les chercheurs norvégiens Ole-Johan Dahl et Kristen Nygaard avec Simula 67, langage incluant les classes et objets, l'héritage, le polymorphisme, etc. Alan Kay en a repris les principes avec Smalltalk, et donna le nom de ce paradigme de programmation. Toutefois, ces principes n'ont été formalisés que pendant les années 1980 et, surtout, 1990. Par exemple le typage de second ordre, qui qualifie le typage de la programmation orientée objet (appelé aussi duck typing), n'a été formulé qu'en 1995 par Cook.

Objet (attributs et méthodes)

Concrètement, un objet est une structure de données qui répond à un ensemble de messages. Cette structure de données définit son état tandis que l'ensemble des messages qu'il comprend décrit son comportement : les données, ou champs, qui décrivent sa structure interne sont appelées ses attributs ; l'ensemble des messages forme ce que l'on appelle l'interface de l'objet ; c'est seulement au travers de celle-ci que les objets interagissent entre eux. La réponse à la réception d'un message par un objet est appelée une méthode (méthode de mise en œuvre du message) ; elle décrit quelle réponse doit être donnée au message.

Certains attributs et/ou méthodes (ou plus exactement leur représentation informatique) sont cachés : c'est le principe d'encapsulation. Ainsi, le programme peut modifier la structure interne des objets ou leurs méthodes associées sans avoir d'impact sur les utilisateurs de l'objet.

Un exemple avec un objet représentant un nombre complexe : celui-ci peut être représenté sous différentes formes (cartésienne (réel, imaginaire), trigonométrique, exponentielle (module, angle)). Cette représentation reste cachée et est interne à l'objet. L'objet propose des messages permettant de lire une représentation différente du nombre complexe. En utilisant les seuls messages que comprend notre nombre complexe, les objets appelants sont assurés de ne pas être affectés lors d'un changement de sa structure interne. Cette dernière n'est accessible que par les méthodes des messages.

Typage et polymorphisme Dans la programmation par objets, chaque objet est typé. Le type définit la syntaxe (« Comment l'appeler ? ») et la sémantique des messages (« Que fait-il ? ») auxquels peut répondre un objet. Il correspond donc, à peu de chose près, à l'interface de l'objet. Toutefois, la plupart des langages objets ne proposent que la définition syntaxique d'un type (C++, Java, C#…) et rares sont ceux qui fournissent aussi la possibilité de définir formellement sa sémantique (comme dans le langage Eiffel avec sa conception par contrats).

Un objet peut appartenir à plus d'un type : c'est le polymorphisme ; cela permet d'utiliser des objets de types différents là où est attendu un objet d'un certain type. Une façon de réaliser le polymorphisme est le sous-typage (appelé aussi héritage de type) : on raffine un type-parent en un autre type (le sous-type) par des restrictions sur les valeurs possibles des attributs. Ainsi, les objets de ce sous-type sont conformes au type parent. De ceci découle le principe de substitution de Liskov. Toutefois, le sous-typage est limité et ne permet pas de résoudre le problème des types récursifs (un message qui prend comme paramètre un objet du type de l'appelant). Pour résoudre ce problème, Cook définit en 1995 la sous-classification et le typage du second ordre qui régit la programmation orientée objet : le type est membre d'une famille polymorphique à point fixe de types (appelée classe). Les traits sont une façon de représenter explicitement les classes de types. (La représentation peut aussi être implicite comme avec Smalltalk, Ruby, etc.).

On distingue dans les langages objets deux mécanismes du typage : le typage dynamique : le type des objets est déterminé à l'exécution lors de la création desdits objets (Smalltalk, Common Lisp, Python, PHP…) ; le typage statique : le type des objets est vérifié à la compilation et est soit explicitement indiqué par le développeur lors de leur déclaration (C++, Java, C#, Pascal…), soit déterminé par le compilateur à partir du contexte (Scala, OCaml…).

De même, deux mécanismes de sous-typage existent : l'héritage simple (Smalltalk, Java, C#) et l'héritage multiple (C++, Python, Common Lisp, Eiffel, WLangage).

Le polymorphisme ne doit pas être confondu avec le sous-typage ou avec l'attachement dynamique ( en anglais).

Redéfinition La programmation objet permet à un objet de raffiner la mise en œuvre d'un message défini pour des objets d'un type parent, autrement dit de redéfinir la méthode associée au message : c'est le principe de redéfinition des messages (ou en anglais).

Or, dans une définition stricte du typage (typage du premier ordre), l'opération résultant d'un appel de message doit être la même quel que soit le type exact de l'objet référé. Ceci signifie donc que, dans le cas où l'objet référé est de type exact un sous-type du type considéré dans l'appel, seule la méthode du type père est exécutée :

Soit un type Reel contenant une méthode * faisant la multiplication de deux nombres réels, soient Entier un sous-type de Reel, i un Entier et r un Reel, alors l'instruction i * r va exécuter la méthode * de Reel. On pourrait appeler celle de Entier grâce à une redéfinition.

Pour réaliser alors la redéfinition, deux solutions existent : le typage du premier ordre associé à l'attachement dynamique (c'est le cas de C++, Java, C#…). Cette solution induit une faiblesse dans le typage et peut conduire à des erreurs. Les relations entre type sont définies par le sous-typage (théorie de Liskov) ; le typage du second ordre (duquel découlent naturellement le polymorphisme et l'appel de la bonne méthode en fonction du type exact de l'objet). Ceci est possible avec Smalltalk et Eiffel. Les relations entre types sont définies par la sous-classification (théorie F-Bound de Cook).

Classe et prototype La structure interne des objets et les messages auxquels ils répondent sont définis par des modules logiciels. Ces mêmes modules créent les objets via des opérations dédiées. Deux représentations existent de ces modules : la classe et le prototype.

La classe est une structure informatique particulière dans le langage objet. Elle décrit la structure interne des données et elle définit les méthodes qui s'appliqueront aux objets de même famille (même classe) ou type. Elle propose des méthodes de création des objets dont la représentation sera donc celle donnée par la classe génératrice. Les objets sont dits alors instances de la classe. C'est pourquoi les attributs d'un objet sont aussi appelés variables d'instance et les messages opérations d'instance ou encore méthodes d'instance. L'interface de la classe (l'ensemble des opérations visibles) forme les types des objets. Selon le langage de programmation, une classe est soit considérée comme une structure particulière du langage, soit elle-même comme un objet (objet non-terminal). Dans le premier cas, la classe est définie dans le runtime ; dans l'autre, la classe a besoin elle aussi d'être créée et définie par une classe : ce sont les méta-classes. L'introspection des objets (ou « méta-programmation ») est définie dans ces méta-classes.

La classe peut être décrite par des attributs et des messages. Ces derniers sont alors appelés, par opposition aux attributs et messages d'un objet, variables de classe et opérations de classe ou méthodes de classe. Parmi les langages à classes on retrouve Smalltalk, C++, C#, Java, etc.