L'encapsulation
getters et setters
Notions théoriques
L'encapsulation
L'encapsulation est le premier pilier de la POO. Elle consiste à :
- Cacher les données internes d'une classe (attributs
private) - Exposer uniquement les opérations autorisées (méthodes
public)
C'est comme une capsule : on ne voit pas l'intérieur, on ne peut interagir qu'avec ce qui est prévu.
// Sans encapsulation : dangereux
public class Personnage {
public int pointsDeVie; // n'importe qui peut écrire hero.pointsDeVie = -9999
}
// Avec encapsulation : sécurisé
public class Personnage {
private int pointsDeVie; // protégé
public void soigner(int points) {
if (points > 0) { // validation
pointsDeVie += points;
}
}
}
Les getters
Un getter est une méthode public qui retourne la valeur d'un attribut private. La convention de nommage en Java est getAttribut() :
private String nom;
private int force;
private boolean vivant;
// Getters
public String getNom() { return nom; }
public int getForce() { return force; }
public boolean isVivant() { return vivant; } // boolean : "is" au lieu de "get"
Pour les attributs de type boolean, la convention est d'utiliser is plutôt que get : isVivant(), isActif(), isEmpty().
Les setters
Un setter est une méthode public qui modifie la valeur d'un attribut private. La convention est setAttribut(Type valeur) :
private String nom;
private int force;
// Setters avec validation
public void setNom(String nom) {
if (nom != null && !nom.isBlank()) {
this.nom = nom;
}
}
public void setForce(int force) {
if (force >= 0) {
this.force = force;
} else {
throw new IllegalArgumentException("La force ne peut pas être négative");
}
}
La validation dans les setters est l'un des grands avantages de l'encapsulation : on garantit que l'objet reste dans un état cohérent.
Générer avec IntelliJ
IntelliJ peut générer automatiquement les getters et setters :
- Placez le curseur dans la classe
- Appuyez sur
Alt+Inser(Windows/Linux) ouCmd+N(Mac) - Choisissez Getter and Setter
- Sélectionnez les attributs pour lesquels générer
Quand ne pas faire de setter ?
Tous les attributs n'ont pas forcément besoin d'un setter. Si une valeur ne doit pas changer après la création de l'objet (par exemple, le nom d'un personnage), ne créez pas de setter. Exposez plutôt des méthodes métier qui décrivent l'action :
// Moins bien : trop générique
public void setPointsDeVie(int pv) { this.pointsDeVie = pv; }
// Mieux : méthodes métier expressives
public void soigner(int points) { this.pointsDeVie += points; }
public void recevoirDegats(int degats) { this.pointsDeVie -= degats; }
Exemple pratique
// Fichier : Personnage.java
public class Personnage {
private String nom;
private int force;
private int defense;
private int pointsDeVie;
private static final int PV_MAXIMUM = 200;
public Personnage(String nom, int force, int defense, int pointsDeVie) {
this.nom = nom;
setForce(force); // utilise le setter pour valider
setDefense(defense);
setPointsDeVie(pointsDeVie);
}
// --- Getters ---
public String getNom() { return nom; }
public int getForce() { return force; }
public int getDefense() { return defense; }
public int getPointsDeVie() { return pointsDeVie; }
public boolean isVivant() { return pointsDeVie > 0; }
// --- Setters avec validation ---
public void setNom(String nom) {
if (nom != null && !nom.isBlank()) {
this.nom = nom;
}
}
public void setForce(int force) {
if (force < 0) throw new IllegalArgumentException("La force doit être positive");
this.force = force;
}
public void setDefense(int defense) {
if (defense < 0) throw new IllegalArgumentException("La défense doit être positive");
this.defense = defense;
}
public void setPointsDeVie(int pointsDeVie) {
this.pointsDeVie = Math.max(0, Math.min(pointsDeVie, PV_MAXIMUM));
}
// --- Méthodes métier ---
public void soigner(int points) {
setPointsDeVie(pointsDeVie + points); // passe par le setter
}
public void recevoirDegats(int degats) {
int effectifs = Math.max(0, degats - defense);
setPointsDeVie(pointsDeVie - effectifs);
System.out.println(nom + " perd " + effectifs + " PV. Restants : " + pointsDeVie);
}
public void afficher() {
System.out.println(nom + " : Force=" + force + ", Def=" + defense + ", PV=" + pointsDeVie);
}
}
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Vous allez transformer la classe Personnage pour encapsuler correctement tous ses attributs avec des getters et des setters validants.
Étape 1 — Getters pour tous les attributs
Ajoutez des getters pour nom, force, defense et pointsDeVie.
Les getters doivent être courts et ne contenir aucune logique métier. Leur rôle est uniquement de lire et retourner une valeur. Toute logique de transformation doit être dans une méthode métier distincte.
Étape 2 — Setter avec validation pour la force
Ajoutez un setter setForce(int force) qui rejette les valeurs négatives avec une exception.
Toujours valider les données entrantes dans les setters. Lancez une IllegalArgumentException avec un message clair si la valeur est invalide. Cela évite que l'objet se retrouve dans un état incohérent (par exemple, une force négative n'a pas de sens dans un jeu RPG).
Étape 3 — Utiliser le setter dans le constructeur
Modifiez le constructeur pour qu'il appelle les setters au lieu d'assigner directement les attributs, afin de bénéficier de la validation dès la création.
En appelant les setters depuis le constructeur (plutôt que d'assigner directement avec this.force = force), vous centralisez la logique de validation en un seul endroit. Si la règle de validation change, vous n'avez à modifier que le setter, pas le constructeur.