Objectifs
- Comprendre le principe d’encapsulation et pourquoi les variables d’instance sont privées.
- Savoir créer des méthodes “getter” et “setter” manuellement pour contrôler l’accès.
- Utiliser les raccourcis
attr_reader,attr_writer, etattr_accessorpour générer automatiquement ces méthodes.
L’encapsulation : Protéger l’état interne
Un principe fondamental de la programmation orientée objet est l’encapsulation. Cela signifie que l’état interne d’un objet (ses variables d’instance @...) doit être considéré comme privé. On ne peut pas y accéder directement depuis l’extérieur de l’objet.
class Personne
def initialize(nom)
@nom = nom
end
end
personne = Personne.new("Alice")
# personne.@nom # -> Erreur ! On ne peut pas accéder directement à @nom.
Pour permettre un accès contrôlé, on crée des méthodes publiques spécifiques.
Getters et Setters : Les portiers de vos données
Le Getter : Pour lire une donnée
Un “getter” est une méthode publique dont le seul rôle est de retourner la valeur d’une variable d’instance. Par convention, elle a le même nom que la variable (sans le @).
class Personne
def initialize(nom)
@nom = nom
end
# Getter manuel
def nom
@nom
end
end
personne = Personne.new("Alice")
puts personne.nom # => "Alice"
Le Setter : Pour modifier une donnée
Un “setter” est une méthode qui permet de modifier la valeur d’une variable d’instance. Par convention, son nom se termine par =.
class Personne
# ... (initialize et getter) ...
# Setter manuel
def nom=(nouveau_nom)
@nom = nouveau_nom
end
end
personne = Personne.new("Alice")
personne.nom = "Alicia" # Syntaxe spéciale qui appelle la méthode nom=
puts personne.nom # => "Alicia"
Les accesseurs : La voie rapide de Ruby
Écrire ces méthodes manuellement est répétitif. Ruby fournit des “macros” (des méthodes qui écrivent du code pour vous) pour les générer automatiquement. On les appelle des accesseurs.
attr_reader : Accès en lecture seule
attr_reader crée automatiquement un “getter” pour vous.
class Personne
attr_reader :nom # Crée la méthode 'nom' pour lire @nom
def initialize(nom)
@nom = nom
end
end
personne = Personne.new("Alice")
puts personne.nom # => "Alice"
# personne.nom = "Alicia" # -> Erreur ! Pas de setter.
attr_writer : Accès en écriture seule
attr_writer crée automatiquement un “setter”. C’est moins courant.
class Personne
attr_writer :nom # Crée la méthode 'nom=' pour écrire dans @nom
# ... (on aurait aussi besoin d'un reader pour afficher le nom)
end
attr_accessor : Lecture ET écriture
C’est le plus utilisé. attr_accessor est un raccourci qui crée à la fois le getter et le setter.
class Personne
# Raccourci pour attr_reader et attr_writer
attr_accessor :nom
def initialize(nom)
@nom = nom
end
end
personne = Personne.new("Alice")
puts personne.nom # => "Alice"
personne.nom = "Alicia"
puts personne.nom # => "Alicia"
On peut déclarer plusieurs accesseurs sur une même ligne : attr_accessor :nom, :age, :ville.
Bonnes pratiques
- Utilisez les accesseurs
attr_*dès que possible. C’est plus concis et plus clair. - N’écrivez un getter/setter manuel que si vous avez besoin d’une logique supplémentaire. Par exemple, un setter qui valide des données avant de les assigner.
- Appliquez le principe du moindre privilège. Si un attribut n’a pas besoin d’être modifié de l’extérieur, n’utilisez qu’un
attr_reader. N’exposez pas plus que ce qui est nécessaire.
Exercices
-
Classe
Livre:- Créez une classe
Livre. - Le
initializedoit prendre untitreet unauteur. - Le
titredoit être lisible et modifiable de l’extérieur. - L’
auteurdoit être seulement lisible. - Utilisez les accesseurs appropriés (
attr_accessor,attr_reader).
- Créez une classe
-
Tester la classe
Livre:- Créez une instance de votre classe
Livre. - Affichez son titre et son auteur.
- Modifiez son titre.
- Essayez de modifier son auteur et observez l’erreur.
- Créez une instance de votre classe
-
Setter personnalisé :
- Créez une classe
Produitavec unattr_readerpour:prix. - Écrivez un setter manuel
prix=qui refuse d’assigner la nouvelle valeur si elle est négative.def prix=(nouveau_prix) if nouveau_prix < 0 puts "Erreur : Le prix ne peut pas être négatif." else @prix = nouveau_prix end end - Testez votre setter en essayant d’assigner un prix positif, puis un prix négatif.
- Créez une classe