Maintenant que les fonctions n’ont plus aucun secret pour vous, nous allons passer à la notion de "classe", que vous devez normalement bien connaître en tant que développeur Java.
Ce n’est pas la taille qui compte
Pour commencer, prenons un exemple simple. Imaginons que nous souhaitions créer une classe User
modélisant un utilisateur de notre programme. En Java, cela donnerait quelque chose comme ça :
public class User {
// PROPERTIES
private String email;
private String password;
private int age;
// CONSTRUCTOR
public User(String email, String password, int age){
this.email = email;
this.password = password;
this.age = age;
}
// GETTERS
public String getEmail() { return email; }
public String getPassword() { return password; }
public int getAge() { return age; }
// SETTERS
public void setEmail(String email) { this.email = email; }
public void setPassword(String password) { this.password = password; }
public void setAge(int age) { this.age = age; }
}
Rien de bien compliqué ici : nous avons créé une classe User
possédant trois propriétés, email
, password
et age
.
Pour "construire" ou plutôt "instancier" une classe afin de créer un objet, nous utilisons un de ses constructeurs. En Java, ce dernier peut s’avérer vite répétitif et n’apporte en soi aucun intérêt logiciel à notre programme : les paramètres sont utilisés pour initialiser les propriétés du même nom dans le corps du constructeur. C’est tout !
De plus, pour récupérer ou modifier les propriétés de notre classe, nous utilisons des assesseurs (ou "getters") et des mutateurs (ou "setters"). Ces derniers peuvent eux aussi devenir vite répétitifs, et prendre beaucoup de place dans notre classe pour pas grand-chose.
Eh bien, en Kotlin, les choses sont bien différentes… Voici la même classe, écrite en Kotlin :
class User(var email: String, var password: String, var age: Int)
Oui, je sais. Tant de lisibilité peut choquer les plus sensibles d’entre vous ; prenez quelques instants pour vous en remettre.
Ça va mieux ? Parfait ! Expliquons en détail cette ligne. Nous utilisons le mot-clé class
pour déclarer une classe en Kotlin, suivi du nom de celle-ci (en l'occurrence, User
). De plus, toutes les propriétés de la classe sont directement renseignées dans des parenthèses, juste après le nom de la classe. Ces parenthèses définissent en réalité le constructeur de la classe (appelé aussi "constructeur primaire") !
Et enfin, nous n’avons pas eu besoin de déclarer un corps à notre classe.
Trop bien ! Mais es-tu sûr que l’exemple en Kotlin représente exactement celui en Java ? Je ne vois pas le mot-clé public
?
Bonne question ! En fait, en Kotlin, la visibilité par défaut de n’importe quel élément de votre code (variables, fonctions, classes, etc.) est public
. D’ailleurs, on retrouve en Kotlin 4 principaux modificateurs de visibilité pour les membres (variables, fonctions, etc.) d’une classe :
private
: Un membre déclaré commeprivate
sera visible uniquement dans la classe où il est déclaré.protected
: Un membre déclaré commeprotected
sera visible uniquement dans la classe où il est déclaré ET dans ses sous-classes (via l’héritage).internal
: Un membre déclaré commeinternal
sera visible par tous ceux du même module. Un module est un ensemble de fichiers compilés ensemble (comme une librairie Gradle ou Maven, par exemple).public
: Un membre déclaré commepublic
sera visible partout et par tout le monde.
Puis, afin d’utiliser cette classe en tant qu’objet (et donc de l’instancier), là aussi la syntaxe est différente :
User user = new User("hello@gmail.com", "azerty", 27)
val user = User("hello@gmail.com", "azerty", 27)
Eh oui, pas besoin de new
en Kotlin pour instancier une classe, ni même du point-virgule pour terminer une instruction (mais ça, vous commencez normalement à en avoir l’habitude).
D’accord ! Mais tu n’as pas déclaré de "getter" ou de "setter" pour la classe User
?
Eh bien si ! Comme vous devez le savoir, le principe d’une classe est d’encapsuler (de cacher, de protéger) un ensemble de données qui ont un certain lien entre elles. Comme ces données sont encapsulées et donc protégées, nous allons avoir besoin d’assesseurs (getters) pour y avoir accès, et de mutateurs (setters) pour les modifier.
En Kotlin, vous n’aurez pas besoin de les déclarer explicitement. Ils seront "générés" automatiquement grâce aux mots-clés val
et var
indiqués avant chaque nom de propriété dans le constructeur de la classe :
val
: La propriété sera immuable, vous ne pourrez donc pas la modifier. Kotlin générera alors pour vous uniquement un assesseur.var
: La propriété sera muable, vous pourrez la modifier. Kotlin générera alors pour vous un assesseur et un mutateur.
Dans notre exemple, toutes les propriétés de notre classe User
auront un assesseur et un mutateur. D’ailleurs, comme nous l’avons vu plus haut, leur visibilité sera par défaut public
.
D’accord, j’ai compris ! Donc, je pourrai y accéder en faisant user.getEmail()
, par exemple ?
Presque ! Vous pourrez le faire encore plus simplement, comme ceci :
val user = User("hello@gmail.com", "azerty", 27)
user.email // Getter
user.email = "new_email@gmail.com" // Setter
Plus besoin d’utiliser les préfixes get
et set
devant le nom d'une propriété : appelez directement la propriété par son nom ! (Et en plus, c’est plus poli… )
Ah ouais ! Mais imaginons que je ne souhaite pas autoriser la modification de la propriété email
, comment dois-je faire ?
Eh bien, vous devrez simplement modifier le constructeur de la classe User
afin de refuser la modification de cette propriété, grâce au mot-clé val
:
class User(val email: String, var password: String, var age: Int)
Maintenant, si nous souhaitons modifier cette propriété, le compilateur va tout simplement lever une belle erreur rouge.
L’évolutivité avant tout !
Nous avons pu voir précédemment le côté "concis" du langage Kotlin, et vous avouerez qu’il serait difficile de faire plus bref en termes de lignes de code écrites.
Cependant, il est probable qu’un jour vous décidiez d’améliorer cette classe, et que vous souhaitiez afficher par exemple dans la console de débogage un message quand l’e-mail d’un utilisateur est récupéré ou affiché.
En Java, cela aurait été facile : vous n’auriez eu qu’à modifier le getter et le setter de la propriété email
. Cependant dans notre précédent exemple en Kotlin, cela sera un poil différent :
class User(email: String, var password: String, var age: Int){
var email: String = email
get() {
println("User is getting their email.");
return field
}
set(value) {
println("User is setting their email");
field = value
}
}
Pas de panique ! Laissez-moi vous expliquer ce que nous venons de faire.
Afin d’avoir accès au getter et au setter de notre propriété email
, il a fallu dans un premier temps retirer le mot-clé val
devant son nom dans le constructeur de la classe : cela permet à Kotlin de le considérer comme un paramètre, et non une propriété.
Puis nous avons déclaré la propriété email
dans le corps de notre classe User
et initialisé celle-ci via le paramètre du même nom situé dans le constructeur. Ensuite, nous avons utilisé les mots-clés get()
et set()
en dessous de cette propriété afin de modifier le comportement de son getter et de son setter.
Le mot-clé field
quant à lui fait référence à la propriété elle-même (sans passer par son getter ou setter, pour éviter bien sûr de boucler à l'infini !) : on appelle d'ailleurs cela le "Backing Field".
Et c’est tout ! Nous venons de personnaliser l’assesseur et le mutateur de la propriété email
.
Mais imaginons que je souhaite déclarer une variable de classe en privé, par exemple le mot de passe d’un utilisateur. Comment dois-je procéder ?
Très bonne question ! Souvenez-vous, dès lors que l’on n'indique aucun modificateur de visibilité, Kotlin met automatiquement cet élément en public
. Si nous souhaitons définir la propriété password
comme étant privée, nous pouvons le faire en rajoutant le mot-clé private
devant sa déclaration :
class User(var email: String, private var passwird: String, var age: Int)
Impossible maintenant d’accéder à la propriété password
, que ce soit via son getter ou son setter.
Practice Makes Perfect!
La théorie, c'est bien, mais la pratique, c'est encore mieux ! Justement, nous vous avons concocté un petit exercice interactif de fin de chapitre pour appliquer toutes ces nouvelles connaissances.
🎓Un petit exercice, ça vous tente ? C'est par ici que ça se passe.
🎁Déjà terminé ? Le corrigé se trouve juste ici.
En résumé
Une classe se déclare grâce au mot-clé
class
.Par défaut, la visibilité d’une classe est
public
en Kotlin.Les propriétés d’une classe peuvent se déclarer directement dans son constructeur primaire.
Le mot-clé
val
placé devant le nom d’une propriété dans le constructeur d’une classe permet d’indiquer à Kotlin de générer automatiquement un assesseur.Le mot-clé
var
placé devant le nom d’une propriété dans le constructeur d’une classe permet d’indiquer à Kotlin de générer automatiquement un assesseur ET un mutateur.
Pour aller plus loin :
KotlinLang : Classes
Vous avez terminé la première partie de ce cours et avez effectué vos premiers pas en Kotlin. Toutes mes félicitations ! 🥳 Dans la prochaine partie, vous découvrirez les structures de contrôle. Mais avant, je vous propose de passer un quiz pour tester vos connaissances !