Java Language
Encapsulation
Recherche…
Introduction
Imaginez que vous ayez une classe avec des variables assez importantes et que celles-ci étaient définies (par d'autres programmeurs à partir de leur code) sur des valeurs inacceptables. Leur code entraînait des erreurs dans votre code. En tant que solution, dans OOP, vous permettez à l'état d'un objet (stocké dans ses variables) d'être modifié uniquement par des méthodes. Le masquage de l'état d'un objet et la fourniture de toutes les interactions via des méthodes d'objets sont connus sous le nom d'encapsulation de données.
Remarques
Il est beaucoup plus facile de commencer par marquer une variable private
et de l'exposer si nécessaire que de masquer une variable déjà public
.
Il existe une exception où l'encapsulation peut ne pas être bénéfique: structures de données "stupides" (classes dont le seul but est de contenir des variables).
public class DumbData {
public String name;
public int timeStamp;
public int value;
}
Dans ce cas, l’interface de la classe est la donnée qu’elle contient.
Notez que les variables marquées comme final
peuvent être marquées comme public
sans violer l'encapsulation, car elles ne peuvent pas être modifiées après avoir été définies.
Encapsulation pour maintenir les invariants
Il y a deux parties d'une classe: l'interface et l'implémentation.
L'interface est la fonctionnalité exposée de la classe. Ses méthodes publiques et ses variables font partie de l'interface.
L'implémentation est le fonctionnement interne d'une classe. Les autres classes ne devraient pas avoir besoin de connaître l'implémentation d'une classe.
L'encapsulation fait référence à la pratique consistant à cacher l'implémentation d'une classe à tous les utilisateurs de cette classe. Cela permet à la classe de formuler des hypothèses sur son état interne.
Par exemple, prenez cette classe représentant un angle:
public class Angle {
private double angleInDegrees;
private double angleInRadians;
public static Angle angleFromDegrees(double degrees){
Angle a = new Angle();
a.angleInDegrees = degrees;
a.angleInRadians = Math.PI*degrees/180;
return a;
}
public static Angle angleFromRadians(double radians){
Angle a = new Angle();
a.angleInRadians = radians;
a.angleInDegrees = radians*180/Math.PI;
return a;
}
public double getDegrees(){
return angleInDegrees;
}
public double getRadians(){
return angleInRadians;
}
public void setDegrees(double degrees){
this.angleInDegrees = degrees;
this.angleInRadians = Math.PI*degrees/180;
}
public void setRadians(double radians){
this.angleInRadians = radians;
this.angleInDegrees = radians*180/Math.PI;
}
private Angle(){}
}
Cette classe repose sur une hypothèse de base (ou invariant ): angleInDegrees et angleInRadians sont toujours synchronisés . Si les membres de la classe étaient publics, il n'y aurait aucune garantie que les deux représentations des angles soient corrélées.
Encapsulation pour réduire le couplage
L'encapsulation vous permet d'apporter des modifications internes à une classe sans affecter le code qui appelle la classe. Cela réduit le couplage ou combien une classe donnée dépend de l'implémentation d'une autre classe.
Par exemple, modifions l'implémentation de la classe Angle à partir de l'exemple précédent:
public class Angle {
private double angleInDegrees;
public static Angle angleFromDegrees(double degrees){
Angle a = new Angle();
a.angleInDegrees = degrees;
return a;
}
public static Angle angleFromRadians(double radians){
Angle a = new Angle();
a.angleInDegrees = radians*180/Math.PI;
return a;
}
public double getDegrees(){
return angleInDegrees;
}
public double getRadians(){
return angleInDegrees*Math.PI / 180;
}
public void setDegrees(double degrees){
this.angleInDegrees = degrees;
}
public void setRadians(double radians){
this.angleInDegrees = radians*180/Math.PI;
}
private Angle(){}
}
L'implémentation de cette classe a été modifiée pour ne stocker qu'une représentation de l'angle et calculer l'autre angle si nécessaire.
Cependant, l'implémentation a changé, mais l'interface ne l'a pas fait . Si une classe appelante comptait sur l'accès à la méthode angleInRadians, elle devrait être modifiée pour utiliser la nouvelle version d' Angle
. Les classes appelantes ne devraient pas se soucier de la représentation interne d'une classe.