Introduction to OOP concepts

Reading time10 min

En bref

Résumé de l’article

Dans cet article, nous présentons les concepts de base liés à la programmation orientée objet (POO). En particulier, nous étudions le concept de classes et d’objets et la manière dont ils sont liés entre eux. Nous nous concentrons ensuite sur deux aspects principaux de la POO : l’encapsulation et l’héritage.

Points clés

  • La programmation orientée objet (POO) est un paradigme de programmation basé sur le concept d’objets, qui peuvent contenir des données et du code : des données sous forme de champs (souvent appelés attributs ou propriétés), et du code sous forme de procédures (souvent appelées méthodes).

  • Les programmes informatiques orientés objet sont conçus comme des objets qui interagissent entre eux.

  • Un objet est une abstraction (logicielle) d’une entité du monde réel impliquée dans l’exécution d’un programme. Il est composé d’une identité, d’un état et d’un comportement.

  • Une classe est une entité qui définit la structure (état ou attributs) et le comportement (méthodes) d’une famille d’objets. Elle se compose d’un nom, d’attributs, de méthodes, et d’un ou plusieurs constructeurs.

  • L’encapsulation est le principe de cacher ou de protéger (une partie de) l’état d’un objet afin qu’il ne puisse pas être directement accessible depuis l’extérieur de la classe.

  • L’héritage est une manière de structurer le code qui définit des relations hiérarchiques entre les classes.

  • Les attributs et méthodes d’une classe parente deviennent automatiquement des attributs et méthodes de ses sous-classes.

  • Les sous-classes peuvent modifier les méthodes de la classe parente (les méthodes de la classe parente peuvent être redéfinies) et en ajouter de nouvelles pour mieux caractériser la sous-classe.

Contenu de l’article

Comme mentionné dans le cours dédié aux paradigmes de programmation, la programmation orientée objet (POO) a été introduite pour faciliter la création et la maintenance de programmes qui résolvent des problèmes complexes. Le principe est très simple : regrouper les données et les actions qui les manipulent dans une même entité, et limiter (voire interdire) l’accès direct aux données. Ces entités sont appelées objets en POO. Le but de ce cours est d’introduire la notion d’objet en POO ainsi que certains concepts associés.

Définition

La programmation orientée objet (POO) est un paradigme de programmation basé sur le concept d’objets, qui peuvent contenir des données et du code : des données sous forme de champs (souvent appelés attributs ou propriétés), et du code sous forme de procédures (souvent appelées méthodes). En POO, les programmes informatiques sont conçus comme des objets qui interagissent entre eux.

1— Objets, attributs et méthodes

Contrairement à la programmation procédurale, un programme écrit en POO répartit l’effort impliqué dans la résolution d’un problème sur un ensemble d’objets qui collaborent en s’envoyant des messages. Un objet est composé de :

  • une identité,
  • un état, représenté par des variables appelées attributs ou propriétés ou champs,
  • un comportement, qui peut modifier l’état et est implémenté par un ensemble de fonctions appelées méthodes.
Définition

Un objet est une abstraction (logicielle) d’une entité du monde réel impliquée dans l’exécution d’un programme.

La figure ci-dessous illustre la différence fondamentale entre la structure d’un programme orienté objet et un programme procédural dans le cas d’un système de gestion de compte bancaire. Dans la version procédurale, le programme est décomposé en plusieurs fonctions qui partagent des données communes (dans notre cas des transactions, avec l’utilisation de tuples pour stocker les paires (utilisateur, montant)). Dans la version orientée objet, les concepts de compte bancaire et d’utilisateur sont implémentés comme des objets.

A bank account management program using OOP vs using procedural programming Figure 1 : Version orientée objet vs version procédurale d’un programme de gestion de compte bancaire.

Les objets interagissent entre eux en s’envoyant des messages, qui peuvent à leur tour être répondus, de sorte qu’ils délèguent certaines tâches à leurs collaborateurs. On dit que les objets interagissent via des appels de méthodes.

Un message :

  • spécifie une méthode (m) de l’objet cible,
  • contient également les arguments (args),
  • est envoyé par un objet source (s) à un objet cible (t) : t.m(args),
  • provoque l’exécution de m(args) de l’objet t,
  • éventuellement t retourne le résultat de m à s,
  • s peut alors continuer son exécution.

En utilisant l’exemple de la Figure 1, si l’utilisateur user_1 souhaite effectuer un dépôt de 500 euros sur le compte bancaire représenté par l’objet bank_account_1, le code de l’objet user_1 contiendra bank_account_1.deposit(user_1, 500) dont l’exécution implique l’envoi du message deposit(user_1, 500) à l’objet bank_account_1.

2— Classes, instanciation et constructeurs

Dans les langages POO, un objet est créé à partir d’une classe. Le terme formel pour la création d’objet est instanciation, les objets étant aussi appelés instances d’une classe. Une classe est une entité qui définit la structure (état ou attributs) et le comportement (méthodes) d’une famille d’objets. Elle se compose de :

  • un nom,
  • des attributs (leur nom et, le cas échéant, leur type),
  • des méthodes (leur nom, type de retour, nom et, le cas échéant, type de chaque argument, et leur code),
  • un constructeur, une méthode particulière appelée lorsqu’un objet est créé et dont le rôle est d’initialiser l’état de l’objet (c’est-à-dire ses attributs).

Par exemple, pour le programme de gestion de compte bancaire, nous pouvons avoir trois classes : BankAccount, User, et Address. Dans la Figure 1, il y a deux objets qui sont des instances de la classe BankAccount, deux instances de la classe User et deux instances de la classe Address.

3— Encapsulation

L’encapsulation est le principe de cacher ou de protéger (une partie de) l’état d’un objet afin qu’il ne puisse pas être accessible depuis l’extérieur de la classe. Il ne peut donc être directement accessible (et modifié) que par les méthodes de l’objet. Cette sécurité de l’état d’un objet :

  • Protège les données internes de l’objet. Par exemple, elle empêche qu’un attribut soit modifié, ou garantit qu’un attribut est mis à jour seulement lorsqu’un autre est modifié.
  • Simplifie l’utilisation de l’objet. Elle ne peut se faire qu’en appelant les méthodes de l’objet, et non en manipulant directement ses attributs.
  • Déconnecte l’utilisation d’un objet de sa structure interne. Puisque les attributs ne sont pas directement accessibles depuis l’extérieur de la classe, il est possible de modifier l’implémentation de l’état d’un objet sans affecter le code des autres objets. Dans notre exemple de programme de gestion de compte bancaire, passer d’une simple liste de transactions contenant le montant d’une opération de dépôt ou de retrait à une liste contenant également des horodatages n’affectera pas le code des objets user.

En conséquence, tout le processus d’exécution d’un programme orienté objet repose sur un principe simple de répartition des responsabilités : chaque objet doit prendre soin de ses propres attributs. Cette programmation est fondamentalement distribuée, modulaire et décentralisée.

4— Héritage

L’héritage est une manière de structurer le code qui définit des relations hiérarchiques entre les classes. Ce concept très simple s’inspire de notre propre manière cognitive de conceptualiser le monde. Par exemple, un ordinateur portable peut être décrit à différents niveaux de précision : une machine, un ordinateur, un notebook, un Lenovo ThinkPad. De même, dans une application orientée objet, on peut créer une classe de base (appelée classe parente) et des sous-classes plus spécifiques (ou classes enfants). Par exemple, considérons le programme du jeu PyRat. La classe Player représente un joueur général (son état est juste un nom et un skin) sans stratégie pour chercher un morceau de fromage dans le labyrinthe. Pour chaque stratégie de parcours de graphe, vous avez créé une nouvelle classe comme sous-classe de Player. Cette technique nous aide à organiser et réutiliser le code efficacement.

Lorsqu’on utilise l’héritage, le code d’une sous-classe peut être :

  • des attributs et méthodes caractérisant la classe parente, car ils deviennent automatiquement des attributs et méthodes de la sous-classe, sans besoin de spécification supplémentaire, c’est-à-dire que les attributs et méthodes d’une classe parente sont hérités par la sous-classe,
  • de nouveaux attributs et méthodes, ajoutés pour mieux caractériser la sous-classe,
  • des méthodes de la classe parente dont le comportement a été modifié, c’est-à-dire que le comportement des méthodes de la classe parente peut être redéfini dans la sous-classe.

Pour aller plus loin

On dirait que cette section est vide !

Y a-t-il quelque chose que vous auriez aimé voir ici ? Faites-le nous savoir sur le serveur Discord ! Peut-être pouvons-nous l’ajouter rapidement. Sinon, cela nous aidera à améliorer le cours pour l’année prochaine !

Pour aller au-delà