Principaux concepts objets
Last updated
Last updated
L'objectif de ce chapitre est de présenter les concepts essentiels de la programmation orientée objet.
Les exemples de code associés sont disponibles en ligne.
Reprenons l'exemple de la classe CompteBancaire
du chapitre précédent.
Tout compte a nécessairement un titulaire, un solde initial et une devise lors de sa création. On aimerait pouvoir instancier un objet de la classe CompteBancaire
en définissant directement les valeurs de ses attributs. Pour cela, nous allons ajouter à notre classe une méthode particulière : le constructeur.
DEFINITION : le constructeur est une méthode spécifique dont le rôle est de construire un objet, le plus souvent en initialisant ses attributs.
ATTENTION : le nom du constructeur doit être identique au nom de la classe, et sa définition ne comporte pas le mot-clé void
.
L'utilisation d'un constructeur se fait au moment de l'instanciation de l'objet (opérateur new
), en passant en paramètres les futures valeurs des attributs de l'objet créé.
Lorsqu'une classe ne définit aucun constructeur (comme dans l'exemple du chapitre précédent), un constructeur par défaut sans aucun paramètre est implicitement créé. Il n'a aucun comportement mais son existence permet d'instancier des objets de cette classe.
En revanche, toute définition explicite d'un constructeur dans une classe "désactive" le constructeur par défaut. Dans notre exemple actuel, on ne peut plus instancier un compte bancaire sans lui fournir les trois paramètres que son constructeur attend.
REMARQUE : une classe peut disposer de plusieurs constructeurs initialisant différents attributs. Nous étudierons cette possibilité dans un prochain chapitre.
L'écriture de classes offre d'autres avantages que le simple regroupement de données et de traitements. Parmi ceux-ci figure la possibilité de restreindre l'accès à certains éléments de la classe. C'est ce que l'on appelle l'encapsulation.
On souhaite qu'un compte bancaire créé ne puisse pas changer de titulaire ni de devise. Cela est possible en définissant les attributs titulaire
et devise
comme étant privés.
A présent, la seule manière de définir des valeurs pour titulaire
et devise
est d'utiliser le constructeur. Toute tentative d'accès externe aux propriétés privées génèrera une erreur lors de la compilation.
Les mots-clés public
et private
permettent de modifier le niveau d'encapsulation (on parle aussi de visibilité ou d'accessibilité) des éléments de la classe (attributs et méthodes) :
un élément public est librement utilisable depuis le reste du programme.
un élément privé est uniquement utilisable depuis les méthodes de la classe elle-même.
REMARQUE : dans de nombreux langages dont le C#, il existe un niveau d'encapsulation intermédiaire (protected
) qui sera étudié plus loin.
DEFINITION : l'encapsulation est l'un des principes fondamentaux de la POO. Il consiste à restreindre l'accès à certains éléments d'une classe (le plus souvent ses attributs). L'objectif de l'encapsulation est de ne laisser accessible que le strict nécessaire pour que la classe soit utilisable.
CONSEIL : sauf cas particulier, on donne le niveau de visibilité private
à tous les attributs d'une classe afin d'assurer leur encapsulation par défaut.
L'encapsulation offre de nombreux avantages :
diminution des risques de mauvaise manipulation d'une classe.
création de classes "boîtes noires" par masquage des détails internes.
possibilité de modifier les détails internes d'une classe (la manière dont elle fonctionne) sans changer son comportement extérieur (ce qu'elle permet de faire).
L'encapsulation des attributs a permis d'interdire toute modification (accidentelle ou volontaire) des données d'un compte bancaire. Cependant, il est maintenant impossible de consulter le solde, le titulaire ou la devise d'un compte créé, ce qui est gênant. On aimerait pouvoir accéder aux données de la classe, tout en maintenant un certain niveau de contrôle. Cela est possible en ajoutant des accesseurs à la classe.
DEFINITION : un accesseur est une méthode le plus souvent publique qui permet d'accéder à un attribut privé.
un accesseur en lecture (getter) permet de lire la valeur d'un attribut.
un accesseur en écriture (mutateur ou setter) permet de modifier la valeur d'un attribut.
En C#, les accesseurs prennent la forme de propriétés. Une propriété se manipule comme un champ, mais il s'agit en réalité d'un couple d'accesseurs get et set. Dans la plupart des autres langages, les accesseurs sont des méthodes de la forme getXXX
et setXXX
.
Voici la classe CompteBancaire
modifiée pour intégrer des accesseurs vers ses attributs, ainsi que son nouveau diagramme de classe.
Depuis la version 3 du langage, on peut définir les propriétés de manière automatique. Dans ce cas, l'attribut disparaît de la définition de le classe : sa présence est implicite. Voici l'exemple précédent réécrit en utilisant des propriétés automatiques.
Cette syntaxe permet de gagner en concision si, comme le plus souvent, les accesseurs se contentent de donner accès à l'attribut sous-jacent sans rien faire de particulier.
DANGER ! Ne pas confondre un champ ou attribut (qui, par convention, commence par une lettre minuscule) avec une propriété au sens du C# (qui commence toujours par une lettre majuscule). Une propriété C# est un accesseur vers un champ.
Voici un exemple d'utilisation des accesseurs définis précédemment.
En remplaçant l'accès direct à un attribut par l'utilisation d'une méthode, un accesseur permet d'effectuer des contrôles supplémentaires : respect d'une plage de valeurs, accès en lecture uniquement, etc.
On observe dans l'exemple ci-dessus qu'il est à nouveau possible de modifier directement les données d'un compte. Pour interdire ces modifications tout en permettant de lire les informations d'un compte, il suffit de supprimer les accesseurs en écriture (setters).
Avec des propriétés automatiques, on peut seulement jouer sur le niveau de visibilité des accesseurs. La version 6 du langage C#, sortie en 2015, permet d'avoir réellement des propriétés automatiques en lecture seule (Plus de détails).
A présent, l'accès aux champs est toujours possible, mais toute tentative de modification des données sera refusée.