Blog ENI : Toute la veille numérique !
🐠 -25€ dès 75€ 
+ 7 jours d'accès à la Bibliothèque Numérique ENI. Cliquez ici
Accès illimité 24h/24 à tous nos livres & vidéos ! 
Découvrez la Bibliothèque Numérique ENI. Cliquez ici
  1. Livres et vidéos
  2. Kotlin
  3. Les classes
Extrait - Kotlin Les fondamentaux du langage
Extraits du livre
Kotlin Les fondamentaux du langage Revenir à la page d'achat du livre

Les classes

Créer une classe

1. Un peu de vocabulaire

Les classes sont très étroitement liées aux objets. En effet, afin de pouvoir créer des objets, nous devons dans un premier temps écrire ce qu’on appelle des classes.

Quelle est la différence entre une classe et un objet ?

Une classe est une structure de données qui permet de décrire un objet. Par exemple, si dans un programme nous souhaitons décrire un chien, il est nécessaire d’écrire une classe qui présente les caractéristiques d’un chien à travers des propriétés (un nom, une taille, une couleur, une race, etc.) et des actions (aboyer, se lécher, se coucher, marcher, etc.).

Un objet, c’est tout simplement un "vrai" chien avec des valeurs associées aux différentes propriétés. Par exemple un chien dont le nom est Rex, dont la taille est de 65 cm, dont la couleur est beige et dont la race est labrador.

On dit alors qu’un objet est une instance de classe. C’est la matérialisation concrète d’une classe.

2. La classe Dog

Dans cette section, nous allons créer une première classe.

 Pour ce faire, rendez-vous dans IntelliJ IDEA.

 Cliquez du bouton droit sur le dossier src/main/kotlin du programme, sélectionnez New puis Kotlin File/Class.

 Dans la boîte de dialogue...

Ajouter des attributs et des méthodes

Jusqu’à présent, nous avons utilisé les termes "propriétés" et "actions" afin d’expliquer ce qu’est un objet. Désormais, nous allons utiliser des mots-clés plus spécifiques à la programmation.

À partir de maintenant, les propriétés seront appelées attributs et les actions seront appelées méthodes. Les attributs sont tout simplement des variables qui sont contenues dans les classes. Les méthodes sont, quant à elles, des fonctions contenues dans les classes.

1. Les attributs

Avant d’écrire les attributs en vue de compléter la classe Dog, il convient de réfléchir aux propriétés qui font qu’un chien est un chien.

Dans un premier temps, un chien sera décrit par les propriétés suivantes :

  • un nom sous la forme d’une chaîne de caractères,

  • un âge sous la forme d’un nombre entier,

  • une race sous la forme d’une chaîne de caractères,

  • une couleur sous la forme d’une chaîne de caractères,

  • une taille en centimètres sous la forme d’un nombre entier,

  • un poids en kilogrammes sous la forme d’un nombre décimal,

  • une position sous la forme d’un caractère : "s" pour sit (assis), "l" pour...

Utiliser des objets

Maintenant que nous avons créé la classe, nous allons l’utiliser. Pour créer une instance de classe et donc un objet, il convient d’utiliser la syntaxe de création des variables, si ce n’est que la partie droite du symbole = est composée du nom de la classe, suivi de parenthèses.

Dans le cas de la classe Dog, la syntaxe est donc la suivante :

fun main() 
{ 
 val labrador = Dog() 
} 

Il est ensuite possible de manipuler les différents attributs, de la même façon que nous accédions à la taille d’un tableau à l’aide la propriété size. Dans les lignes de code suivantes, nous donnons des valeurs cohérentes à l’ensemble des attributs d’une instance de la classe Dog :

val labrador = Dog() 
labrador.name = "Doggo" 
labrador.weight = 12.5f 
labrador.age = 4 
labrador.color = "brown" 
labrador.race = "labrador" 
labrador.size = 180 
labrador.position = 's' 

Il est également possible d’appeler les différentes méthodes de la classe :

labrador.bark() 
println(labrador.weight) 
labrador.eat(100) 
println(labrador.weight) 
labrador.run(2000) 
println(labrador.weight) 

Afficher un objet

Essayons maintenant d’afficher un objet dans le terminal via la méthode println en exécutant le programme ci-après :

val labrador = Dog() 
labrador.name = "Doggo" 
labrador.weight = 12.5f 
labrador.age = 4 
labrador.color = "brown" 
labrador.race = "labrador" 
labrador.size = 180 
labrador.position = 's' 
 
println(labrador) 

Du côté du terminal, le résultat est peu compréhensible :

Dog@610455d6 

Pour faire simple, il s’agit de l’identifiant unique de l’objet dans la machine virtuelle Java (JVM). Il est en réalité très facile d’afficher une forme bien plus lisible d’un objet. Pour ce faire, procédez comme suit :

 Dans la classe Dog, cliquez du bouton droit dans la partie sur la zone d’édition du code source.

 Dans le menu qui s’ouvre, sélectionnez Generate puis, dans le nouveau menu, choisissez toString().

La boîte de dialogue suivante s’affiche :

images/09RI02.PNG

Le but ici est de sélectionner les attributs de la classe qui seront affichés dans la console à l’exécution du println.

 Dans le cas présent, sélectionnez-les tous, puis cliquez sur le bouton OK.

La méthode suivante s’ajoute alors automatiquement à la classe :

override...

Les droits d’accès

1. Les méthodes

L’exemple précédent permet d’accéder aux attributs et aux méthodes de la classe depuis un autre fichier. Aussi, tous les attributs peuvent être lus et modifiés. 

En réalité, ce comportement peut, dans certains cas, poser des problèmes d’intégrité. En effet, imaginons que la modification de la valeur d’un attribut d’un objet ne puisse se faire qu’après certaines vérifications. Par exemple, pour modifier l’âge ou le poids d’un chien, il faut vérifier préalablement que la valeur à affecter est strictement positive :

val age = 4 
 
val labrador = Dog() 
 
if(age > 0) 
{ 
 labrador.age = age 
} 

Une telle solution fonctionne, mais elle n’est pas maintenable. En effet, dans un programme conséquent, il n’est pas envisageable d’écrire cette condition à chaque fois si le code ne se trouve pas dans une fonction dédiée à cette vérification. D’autant plus que si l’on souhaite faire évoluer cette règle métier, il conviendra de modifier l’ensemble du code pour la modifier. 

La solution consiste à faire porter cette règle métier par la classe Dog et à faire en sorte...

Les mutateurs et les accesseurs

Pour répondre à notre besoin de la précédente section qui est la lecture de l’attribut age depuis l’extérieur de l’objet tout en conservant une modification uniquement depuis l’intérieur de celui-ci, il convient de définir un droit d’accès public en lecture et un droit d’accès privé en écriture.

Il est possible de traduire autrement ce besoin. La lecture se fait via un accesseur (pour accéder à la valeur) qui doit être public alors que l’écriture se fait via un mutateur (pour modifier la valeur) qui doit être privé.

Exemple

class Dog 
{ 
 
 //... 
 
 var age = 0 
  public get 
  private set 
 
 //... 
 
} 

Sous la déclaration de l’attribut age, nous avons ajouté deux lignes. La première, public get, permet de dire que l’accesseur est public. La seconde, private set, permet de dire que le mutateur est privé.

On utilise ici le mot-clé get pour l’accesseur car en anglais on appelle ça un getter.

Dans ce cas précis, puisque l’accesseur de l’attribut age est public et que l’attribut est lui-même public, il n’est pas nécessaire de le préciser. Nous pouvons nous limiter...

Les constructeurs

Pour instancier un objet et donner une valeur à l’ensemble de ses attributs, nous avons utilisé une syntaxe un peu laborieuse :

val labrador = Dog() 
labrador.name = "Doggo" 
labrador.weight = 12.5f 
labrador.age = 4 
labrador.color = "brown" 
labrador.race = "labrador" 
labrador.size = 180 
labrador.position = 's' 

Non seulement la répétition de la variable labrador est laborieuse, mais cette syntaxe peut introduire des erreurs. Comment être sûr d’avoir initialisé tous les attributs ? Que se passe-t-il si après des mois de développement nous décidons d’ajouter un nouvel attribut ? Faut-il revenir sur toutes les instances d’objets pour s’assurer que ce nouvel attribut est correctement initialisé ? Probablement. Mais comment être sûr de n’en oublier aucune ?

C’est pour répondre à toutes ces problématiques qu’il existe les constructeurs, un concept essentiel à la programmation orientée objet.

Un constructeur permet de construire un objet. Il est automatiquement appelé lors de l’instanciation d’un objet. Nous avons en réalité déjà utilisé des constructeurs sans le savoir dans le chapitre Les tableaux.

Reprenons l’objet labrador :

val labrador = Dog() 

C’est la présence des parenthèses juste après le nom de la classe qui permet d’invoquer le constructeur de la classe Dog.

Jusqu’à maintenant, nous n’avons jamais écrit de constructeur car chaque classe vient avec ce qu’on appelle un constructeur par défaut. Ce constructeur est vide. Il ne permet donc pas d’initialiser les attributs d’une classe. C’est pour cela qu’il est très souvent nécessaire d’écrire ses propres constructeurs.

1. Créer un constructeur

Nous allons créer un constructeur qui permet d’initialiser les différents attributs de la classe Dog suivante :

class Dog 
{ 
 
 var age = 0 
 
 var name = "" 
 
 var race = "" 
 
 var color = "" 
 
 var size = 0 
 
 var weight = 0f ...

En résumé

  • Pour créer des objets, il est nécessaire de modéliser leurs attributs et leurs méthodes dans une classe.

  • Il est possible de définir des droits d’accès aux différents éléments qui composent une classe.

  • Il est possible de définir des mutateurs et des accesseurs rattachés aux différents attributs d’une classe.

  • Il est possible de créer un ou plusieurs constructeurs afin d’initialiser les attributs d’un objet avec des valeurs spécifiques.