Java Language
incapsulamento
Ricerca…
introduzione
Immagina di avere una classe con alcune variabili piuttosto importanti e che siano state impostate (da altri programmatori dal loro codice) a valori inaccettabili. Il loro codice ha causato errori nel codice. Come soluzione, in OOP, si consente di modificare lo stato di un oggetto (memorizzato nelle sue variabili) solo tramite i metodi. Nascondere lo stato di un oggetto e fornire tutte le interazioni attraverso i metodi di un oggetto è noto come Incapsulamento dei dati.
Osservazioni
È molto più semplice iniziare a contrassegnare una variabile private
e esporla se necessario piuttosto che nascondere una variabile già public
.
Esiste un'eccezione in cui l'incapsulamento potrebbe non essere vantaggioso: strutture di dati "stupide" (classi il cui unico scopo è quello di contenere variabili).
public class DumbData {
public String name;
public int timeStamp;
public int value;
}
In questo caso, l'interfaccia della classe è i dati che contiene.
Si noti che le variabili contrassegnate come final
possono essere contrassegnate come public
senza violare l'incapsulamento perché non possono essere modificate dopo essere state impostate.
Incapsulamento per mantenere invarianti
Ci sono due parti di una classe: l'interfaccia e l'implementazione.
L'interfaccia è la funzionalità esposta della classe. I suoi metodi e variabili pubblici sono parte dell'interfaccia.
L'implementazione è il funzionamento interno di una classe. Altre classi non dovrebbero avere bisogno di conoscere l'implementazione di una classe.
L'incapsulamento si riferisce alla pratica di nascondere l'implementazione di una classe da qualsiasi utente di quella classe. Ciò consente alla classe di formulare ipotesi sul suo stato interno.
Ad esempio, prendi questa classe che rappresenta un angolo:
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(){}
}
Questa classe si basa su un'ipotesi di base (o invariante ): angleInDegrees e angleInRadians sono sempre sincronizzati . Se i membri della classe fossero pubblici, non ci sarebbe alcuna garanzia che le due rappresentazioni degli angoli siano correlate.
Incapsulamento per ridurre l'accoppiamento
Incapsulamento consente di apportare modifiche interne a una classe senza influire sul codice che chiama la classe. Questo riduce l' accoppiamento , o quanto una determinata classe si basa sull'implementazione di un'altra classe.
Ad esempio, cambiamo l'implementazione della classe Angle dall'esempio precedente:
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'implementazione di questa classe è cambiata in modo che memorizzi solo una rappresentazione dell'angolo e calcola l'altro angolo quando necessario.
Tuttavia, l'implementazione è cambiata, ma l'interfaccia no . Se una classe chiamante si affidava all'accesso al metodo angleInRadians, avrebbe dovuto essere modificata per utilizzare la nuova versione di Angle
. Le classi di chiamata non dovrebbero preoccuparsi della rappresentazione interna di una classe.