5.2. Indkapsling

Indkapsling af data og metoder i objekter betyder, at man ikke lader andre bruge objekterne helt efter eget forgodtbefindende. Man gør visse dele af objekterne utilgængelige uden for klassens metoder. Herved sætter man nogle regler op for, hvordan man kan benytte objekterne.

Hvorfor overhovedet indkapsle (skjule) variabler?

Indkapsling i klasser er vigtig, når programmerne bliver store og komplekse. Hvis det er muligt at ændre data i en klasse, se eksemplet ovenfor, kan det føre til situationer, som kommer ud af kontrol i store komplekse systemer.

Ved at indkapsle data er den eneste måde at ændre data på brugen af metoder. I metoderne kan man sikre sig mod vanvittige overgreb på variabler ved at tilføre logik, der sikrer, at variablerne er konsistente.

I ovenstående eksempel kan man for eksempel sætte højden af en boks til et negativt tal. Spørger man derefter på volumen(), vil man få et negativt svar! Det kræver ikke meget fantasi at forestille sig, hvordan sådanne fejl kunne gøre et program ubrugeligt. Tænk for eksempel på pakkepost-omdeling, hvis et af Post Danmarks programmer påstod, at der nemt kunne være 10001 pakker på hver minus en kubikmeter og 10000 pakker på hver plus en kubikmeter i én postvogn... endda med flere kubikmeter til overs til anden post!

Med indkapsling opnår man at objekterne altid er konsistente, fordi objekterne selv sørger for at deres variabler har fornuftige værdier.

Man styrer "synligheden" af en variabel eller metode med nøgleordene public og private:

public betyder "synlig for alle"

private betyder "kun synlig i klassen"

Herunder ses en modificeret version af eksemplet med Boks- og BenytBoks-klassen, men nu er variablerne erklæret private.


public class Boks2
{
  private double længde;
  private double bredde;
  private double højde;

  public void sætMål(double lgd, double b, double h)
  {
    if (lgd<=0 || b<=0 || h<=0)
    {
       System.out.println("Ugyldige mål. Bruger standardmål.");
      længde = 10.0;
      bredde = 10.0;
      højde  = 10.0;
    } else {
      længde = lgd;
      bredde = b;
      højde  = h;
    }
  }

  public double volumen()
  {
    double vol;
    vol = længde*bredde*højde;
    return vol; 
  }
}

Klassen er illustreret med UML nedenfor. Bemærk, at variablerne er private, så de har et - foran, mens metoderne, som kan ses udefra (public), har et + foran:

Figur 5-2. Java

Nu da variablerne bredde, højde og længde er erklæret private, er det ulovligt at ændre dem "udefra", i vores BenytBoks-program.

Til gengæld har vi defineret metoden sætMål(), som man kan kalde for at sætte målene. Nu da den eneste måde at ændre data på er ved specifikt at kalde metoden sætMål(), kan vi indlægge en ønsket logik - for eksempel sikre os mod 0 (nul) eller negative værdier.


public class BenytBoks2
{
  public static void main(String args[])
  {
    Boks2 enBoks = new Boks2();

    //ulovligt: enBoks.længde= 12.3;
    //ulovligt: enBoks.bredde= 2.22;
    //ulovligt: enBoks.højde= 6.18;

    enBoks.sætMål( 2.0, 2.5, 1.5);

    System.out.println("Volumen er: "+ enBoks.volumen());

    enBoks.sætMål(-2.0, 0.0, 1.0);

    System.out.println("Volumen er: "+ enBoks.volumen());

    enBoks.sætMål( 2.0, 3.0 ,1.0);

    System.out.println("Volumen er: "+ enBoks.volumen());
  }
}

Volumen er: 7.5
Ugyldige mål. Bruger standardmål.
Volumen er: 1000.0
Volumen er: 6.0

En anden fordel ved indkapsling er, at man bliver uafhængig af repræsentationen. Man kunne f.eks. gemme volumen i Boks-klassen i stedet for højden og så lade højden være beregnet.