Java Language
inkapsling
Sök…
Introduktion
Föreställ dig att du hade en klass med några ganska viktiga variabler och de ställdes in (av andra programmerare från deras kod) till oacceptabla värden. Deras kod gav fel i din kod. Som en lösning, I OOP tillåter du att ett objekts tillstånd (lagrat i dess variabler) endast kan ändras genom metoder. Dölja ett objekts tillstånd och tillhandahålla all interaktion genom ett objektmetoder kallas Data Encapsulation.
Anmärkningar
Det är mycket lättare att börja med att markera en variabel private
och exponera den vid behov än att dölja en redan public
variabel.
Det finns ett undantag där inkapsling kanske inte är till nytta: "dumma" datastrukturer (klasser vars enda syfte är att hålla variabler).
public class DumbData {
public String name;
public int timeStamp;
public int value;
}
I det här fallet, är gränssnittet i klassen data som det innehar.
Observera att variabler som är markerade som final
kan markeras public
utan att bryta mot inkapslingen eftersom de inte kan ändras efter att de har ställts in.
Inkapsling för att upprätthålla invarianter
Det finns två delar av en klass: gränssnittet och implementeringen.
Gränssnittet är klassens exponerade funktionalitet. Dess offentliga metoder och variabler är en del av gränssnittet.
Implementeringen är de interna funktionerna i en klass. Andra klasser borde inte behöva veta om genomförandet av en klass.
Inkapsling avser praxis att dölja implementeringen av en klass för alla användare av den klassen. Detta gör det möjligt för klassen att göra antaganden om sitt interna tillstånd.
Ta till exempel den här klassen som representerar en vinkel:
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(){}
}
Denna klass förlitar sig på ett grundläggande antagande (eller invariant ): angleInDegrees och angleInRadians är alltid synkroniserade . Om klassmedlemmarna var offentliga skulle det inte finnas några garantier för att de två vinklarnas föreställningar är korrelerade.
Inkapsling för att minska kopplingen
Inkapsling låter dig göra interna ändringar i en klass utan att påverka någon kod som kallar klassen. Detta minskar kopplingen , eller hur mycket en viss klass förlitar sig på implementeringen av en annan klass.
Låt oss till exempel ändra implementeringen av vinkelklassen från föregående exempel:
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(){}
}
Implementeringen av denna klass har förändrats så att den bara lagrar en representation av vinkeln och beräknar den andra vinkeln när det behövs.
Implementeringen ändrades dock, men gränssnittet gjorde det inte . Om en anropsklass förlitade sig på åtkomst till metoden angleInRadians, skulle den behöva ändras för att använda den nya versionen av Angle
. Att ringa klasser ska inte bry sig om den interna representationen av en klass.