Le problème : la porte grande ouverte
À la leçon précédente, on fabriquait des comptes avec une méthode deposer() qui contient les règles. Sauf que rien n'empêche d'écrire, ailleurs dans le code :
compte.solde = 999999; // on contourne deposer() et toutes ses règles
compte.solde = -500; // un solde négatif ? pourquoi pas, personne ne vérifie
Si n'importe qui peut modifier le solde directement, tes garde-fous ne servent à rien. Le jour où un bout de code (le tien, ou celui d'un collègue) écrit une valeur incohérente, tu auras un bug impossible à retrouver : qui a mis ce solde à -500, et où ? C'est exactement le genre de chaos que la POO veut éviter.
L'idée : cacher l'intérieur, n'exposer qu'une porte
L'encapsulation, c'est fermer l'objet : ses données deviennent privées (inaccessibles de l'extérieur), et la seule façon d'agir dessus est de passer par ses méthodes publiques, qui imposent les règles. L'objet devient une capsule : on voit les boutons, pas les rouages.
L'image juste, c'est le distributeur de boissons. Tu appuies sur un bouton (méthode publique), la machine te sort une canette. Tu n'ouvres pas la machine pour prendre une canette à la main, et tu ne touches pas à la caisse à l'intérieur (donnée privée). L'interface est réduite et contrôlée : c'est ce qui rend la machine fiable.
En code : private, public, et les accesseurs
On marque les données privées (souvent private, ou un # en JavaScript) et les méthodes utiles publiques. Pour lire une donnée privée sans permettre de l'écrire n'importe comment, on expose un accesseur (un « getter ») :
classe Compte:
privé solde = 0 // inaccessible de l'extérieur
public deposer(montant):
si montant > 0: // la règle vit ici, impossible à contourner
this.solde += montant
public retirer(montant):
si montant > 0 et montant <= this.solde:
this.solde -= montant
public lireSolde(): // accesseur : on peut LIRE, pas écrire
retourne this.solde
compte.solde = 999999 // ❌ refusé : solde est privé
compte.deposer(50) // ✅ seule voie autorisée
Bénéfice immédiat : il n'existe qu'un seul endroit où le solde change (les méthodes). Un solde incohérent devient impossible, pas juste « pas censé arriver ». Et tu peux changer l'intérieur (stocker en centimes, ajouter un journal…) sans rien casser dehors, tant que les portes ne changent pas.
La capsule en vrai (essaie de tricher)
Ce Compte garde son solde en privé (un vrai champ privé JS #solde). Essaie la voie normale… puis essaie de tricher en écrivant le solde directement.
Ce que l'encapsulation t'apporte
- Des invariants garantis : un solde négatif devient impossible, pas juste déconseillé.
- Un seul endroit à débugger : si le solde est faux, le coupable est forcément dans une méthode de la classe.
- La liberté de changer l'intérieur : tant que les méthodes publiques gardent la même signature, tu refais la cuisine interne sans casser le reste du programme.
Règle d'or : expose le minimum. Données privées par défaut, méthodes publiques seulement pour ce dont l'extérieur a vraiment besoin. Une petite surface publique = un objet facile à comprendre, à utiliser et à faire évoluer.
Tu demandes à l'IA d'« encapsuler » la classe Compte. Elle te rend ceci. Ton rôle de relecteur : l'accepter telle quelle ou la rejeter, et dire pourquoi.
class Compte {
#solde = 0;
get solde(){ return this.#solde; }
set solde(v){ this.#solde = v; } // setter public, sans contrôle
}
compte.solde = -500; // passe : le setter ne vérifie rien
#solde est bien privé, mais le set solde(v) rouvre la porte en grand : depuis l'extérieur, compte.solde = -500 passe sans aucun contrôle. C'est de la fausse encapsulation : on a juste déplacé l'accès direct dans un setter sans règle. Un getter en lecture seule, oui ; un setter public sans validation revient à rendre la donnée publique. Garde le get, supprime le set, et fais passer les écritures par deposer() / retirer() qui imposent les invariants.Sans remonter dans la leçon : qu'est-ce que l'encapsulation, et pourquoi rendre solde privé protège-t-il mieux qu'un simple commentaire « ne pas toucher » ?
solde privé est plus fort qu'un commentaire parce que c'est garanti par le langage : compte.solde = -500 est refusé, pas juste déconseillé. Résultat : un seul endroit où le solde change, donc un invariant garanti et un seul endroit à débugger.privée plutôt que publique ?Tes objets sont solides et bien fermés. Maintenant, comment créer un CompteÉpargne qui fait presque comme un Compte, mais avec un taux d'intérêt en plus, sans tout réécrire ? C'est le rôle de l'héritage.
The problem: the wide-open door
In the previous lesson, we built accounts with a deposer() method holding the rules. Except nothing stops you from writing, elsewhere in the code:
account.solde = 999999; // we bypass deposer() and all its rules
account.solde = -500; // a negative balance? sure, nobody checks
If anyone can change the balance directly, your safeguards are useless. The day some code (yours, or a colleague's) writes an inconsistent value, you'll have a bug that's impossible to track: who set this balance to -500, and where? That's exactly the chaos OOP wants to avoid.
The idea: hide the inside, expose only a door
Encapsulation means closing the object: its data becomes private (unreachable from outside), and the only way to act on it is through its public methods, which enforce the rules. The object becomes a capsule: you see the buttons, not the gears.
The right image is the vending machine. You press a button (public method), the machine hands you a can. You don't open the machine to grab a can by hand, and you don't touch the cash inside (private data). The interface is small and controlled: that's what makes the machine reliable.
In code: private, public, and accessors
We mark the data private (often private, or a # in JavaScript) and the useful methods public. To read a private value without allowing it to be written carelessly, we expose an accessor (a "getter"):
class Account:
private balance = 0 // unreachable from outside
public deposit(amount):
if amount > 0: // the rule lives here, impossible to bypass
this.balance += amount
public withdraw(amount):
if amount > 0 and amount <= this.balance:
this.balance -= amount
public getBalance(): // accessor: you can READ, not write
return this.balance
account.balance = 999999 // ❌ refused: balance is private
account.deposit(50) // ✅ the only allowed way
Immediate benefit: there is a single place where the balance changes (the methods). An inconsistent balance becomes impossible, not just "shouldn't happen". And you can change the inside (store cents, add a log…) without breaking anything outside, as long as the doors stay the same.
The capsule for real (try to cheat)
This Compte keeps its balance private (a real JS private field #solde). Try the normal way… then try to cheat by writing the balance directly.
What encapsulation gives you
- Guaranteed invariants: a negative balance becomes impossible, not just discouraged.
- A single place to debug: if the balance is wrong, the culprit is necessarily inside a method of the class.
- Freedom to change the inside: as long as the public methods keep the same signature, you redo the internal plumbing without breaking the rest of the program.
Golden rule: expose the minimum. Data private by default, public methods only for what the outside truly needs. A small public surface = an object that's easy to understand, use and evolve.
Your objects are solid and well-closed. Now, how do you create a SavingsAccount that behaves almost like an Account, but with an extra interest rate, without rewriting everything? That's the role of inheritance.