Au Chapitre 2 on a rendu les attributs privés — et cassé tout le code qui les utilisait. Il faut maintenant rouvrir des points d'accès, mais de manière contrôlée. La solution classique, qu'on retrouve dans tous les langages objet, consiste à fournir une méthode pour lire (le getter) et une méthode pour écrire (le setter).
Tu as vu au chapitre précédent que private ferme l'accès direct aux attributs. Cette barrière est utile — mais il faut quand même un moyen de lire et d'écrire ces données depuis l'extérieur. Les getters et setters sont la première réponse à ce besoin.
À la fin de ce chapitre, tu seras capable de :
Reprenons l'exemple du Personnage :
class Personnage
{
private string nom;
private int pv;
private int pvMax;
private int niveau;
}
Avec ces attributs private, le code suivant ne compile plus :
Personnage hero = new Personnage();
hero.nom = "Aragorn"; // ❌ inaccessible
hero.pv = 100; // ❌ inaccessible
Pour que Program.cs puisse encore travailler avec un personnage, il faut fournir des méthodes publiques qui font le pont entre l'extérieur et les attributs internes. C'est tout ce qu'est un getter ou un setter : une méthode public qui touche un attribut private.
Un getter est une méthode qui renvoie la valeur d'un attribut. Par convention, son nom commence par Get suivi du nom de l'attribut.
class Personnage
{
private int pv;
public int GetPv()
{
return pv;
}
}
Côté Program.cs :
Personnage hero = new Personnage();
Console.WriteLine(hero.GetPv()); // 0 (la valeur par défaut d'un int)
public : la méthode est appelable depuis l'extérieur.int : c'est le type de ce que la méthode renvoie (un entier, comme l'attribut).GetPv() : pas de paramètre — on demande juste à lire.return pv; : on renvoie l'attribut privé.💡 Pourquoi écrire une méthode juste pour renvoyer un attribut ? Tant qu'elle ne fait que
return, en effet elle n'apporte presque rien. Mais elle a un avantage caché : si un jour la lecture devient plus complexe (par exemple lire depuis un fichier, ou recalculer la valeur), on n'a qu'un seul endroit à modifier. Le code appelant continue d'appelerhero.GetPv()sans rien changer.
Un setter est une méthode qui affecte une nouvelle valeur à un attribut. Son nom commence par Set suivi du nom de l'attribut. Il prend un paramètre — la nouvelle valeur — et ne renvoie rien (void).
public void SetPv(int valeur)
{
pv = valeur;
}
Côté Program.cs :
hero.SetPv(100);
Console.WriteLine(hero.GetPv()); // 100
void : la méthode ne renvoie rien.int valeur : le paramètre — la valeur qu'on essaie d'affecter.pv = valeur; : on assigne effectivement.À ce stade, ce setter ne fait que recopier la valeur — il n'apporte pas grand-chose de plus qu'un attribut public aurait fait.
Sauf que. Maintenant qu'on contrôle l'écriture, on peut y ajouter ce qu'on veut.
Voici l'intérêt majeur du setter. Avant d'affecter la valeur, on peut la vérifier et la corriger si nécessaire.
public void SetPv(int valeur)
{
if (valeur < 0) valeur = 0; // pas de PV négatifs
if (valeur > pvMax) valeur = pvMax; // pas plus que le max
pv = valeur;
}
Maintenant, regarde ce qui se passe :
hero.SetPvMax(100);
hero.SetPv(120); // demande 120, mais sera plafonné à 100
hero.SetPv(-9999); // demande -9999, mais sera ramené à 0
Console.WriteLine(hero.GetPv()); // 0
Le code appelant peut bien essayer ce qu'il veut. L'objet refuse silencieusement, et reste dans un état cohérent. C'est précisément ce qu'on voulait depuis le Chapitre 2.
🧠 À retenir : un setter sans validation, c'est un attribut public déguisé. Tout l'intérêt est dans le code qu'on peut placer avant l'affectation.
| Attribut | Validation typique |
|---|---|
pv |
valeur < 0 → 0 ; valeur > pvMax → pvMax |
niveau |
valeur < 1 → 1 |
nom |
valeur == "" ou null → "Inconnu" |
intensiteLampe |
valeur < 0 → 0 ; valeur > 100 → 100 |
solde (compte) |
refuser un retrait qui passerait en négatif |
Personnage au completVoici à quoi ressemble la classe avec tous ses getters et setters :
class Personnage
{
// --- Attributs privés ---
private string nom;
private int pv;
private int pvMax;
private int niveau;
// --- Getters ---
public string GetNom() { return nom; }
public int GetPv() { return pv; }
public int GetPvMax() { return pvMax; }
public int GetNiveau() { return niveau; }
// --- Setters avec validation ---
public void SetNom(string valeur)
{
if (valeur == "" || valeur == null) valeur = "Inconnu";
nom = valeur;
}
public void SetPv(int valeur)
{
if (valeur < 0) valeur = 0;
if (valeur > pvMax) valeur = pvMax;
pv = valeur;
}
public void SetPvMax(int valeur)
{
if (valeur < 1) valeur = 1;
pvMax = valeur;
}
public void SetNiveau(int valeur)
{
if (valeur < 1) valeur = 1;
niveau = valeur;
}
}
Et l'utilisation côté Program.cs :
Personnage hero = new Personnage();
hero.SetNom("Aragorn");
hero.SetPvMax(100);
hero.SetPv(100);
hero.SetNiveau(5);
Console.WriteLine($"{hero.GetNom()} - Niv.{hero.GetNiveau()} - {hero.GetPv()}/{hero.GetPvMax()} PV");
// Aragorn - Niv.5 - 100/100 PV
Regarde bien la classe ci-dessus. Pour 4 attributs, on a écrit 8 méthodes. Pour 6 attributs, ce serait 12 méthodes. Et chaque utilisation devient hero.GetX() au lieu de hero.X — plus long à lire, plus long à taper.
C'est la grande limite de cette approche :
⚠️ Les getters/setters explicites alourdissent énormément le code. Une classe qui devrait tenir en 15 lignes en fait 60.
Tous les langages objet ont ce problème. Java, PHP, Python… acceptent cette verbosité comme un mal nécessaire. C# a fait un choix différent : proposer une syntaxe plus courte qui fait la même chose.
C'est l'objet du chapitre suivant : les propriétés.
Reprends ta classe Voiture du Chapitre 1. Passe tous les attributs en private et fournis pour chacun un getter et un setter.
Ajoute au moins une validation :
NombreDePortes : entre 2 et 5 (sinon ramener à 5 par défaut).Couleur : refuser une chaîne vide (par défaut "Inconnue").Teste depuis Program.cs :
maVoiture.SetNombreDePortes(-12);
Console.WriteLine(maVoiture.GetNombreDePortes()); // doit afficher 5
Crée une classe CompteBancaire avec :
private string titulaireprivate double soldeEt les méthodes suivantes :
| Méthode | Comportement |
|---|---|
GetTitulaire() |
retourne le nom du titulaire |
GetSolde() |
retourne le solde |
SetTitulaire(string) |
refuse une chaîne vide |
Deposer(double montant) |
ajoute au solde si le montant est positif |
Retirer(double montant) |
retire du solde si le solde reste ≥ 0 après l'opération |
Note : Deposer et Retirer ne sont pas des setters classiques — ce sont des méthodes métier. Mais elles touchent l'attribut privé solde exactement de la même façon : avec validation. C'est une des forces de l'encapsulation — tout passage par la classe est l'occasion de contrôler.
Pour la classe Personnage complète de la Partie 5 :
force, agilite), combien de lignes en plus ?public int GetX() { return x; }.public void SetX(int v) { ... x = v; }.On a maintenant des données privées et des accès contrôlés — mais le code paie ça en verbosité. Au chapitre suivant, on découvre les propriétés C# : une syntaxe spécifique au langage qui fait exactement ce que font les getters/setters, en deux ou trois fois moins de lignes, et avec une utilisation presque transparente côté Program.cs.