Inkapsling handlar om att skydda ett objekts interna tillstånd och bara exponera det som är nödvändigt via publika metoder. Detta är en av de viktigaste principerna i OOP.


Varför inkapsling?

Utan inkapsling kan vem som helst manipulera ett objekts interna data hur som helst:

// DÅLIGT — ingen inkapsling
Bankkonto konto = new Bankkonto();
konto.saldo = -5000; // Negativt saldo tillåtet! Inget skydd!

Med inkapsling kan du lägga till regler och validering:

// BRA — inkapsling med privata fält och publika metoder
Bankkonto konto = new Bankkonto(1000);
konto.uttag(200);     // fungerar
konto.uttag(5000);    // kastar fel — otillräckligt saldo
// konto.saldo = ...; // GÅR INTE — private

Synlighetsmodifierare

De flesta OOP-språk har tre eller fyra nivåer av synlighet:

ModifierareSamma klassSamma paketSubklassAlla
privateJaNejNejNej
default (ingen)JaJaNejNej
protectedJaJaJaNej
publicJaJaJaJa
public class Exempel {
    private int a;       // bara inom denna klass
    int b;               // default — inom samma paket
    protected int c;     // + subklasser oavsett paket
    public int d;        // överallt
}

Tumregel: Gör allt private som standard. Öppna upp (protected/public) bara när du har ett konkret behov där inte setters eller getters skulle fungera.


Getters och Setters

Det vanligaste sättet att implementera inkapsling är via getters och setters — publika metoder som läser och skriver privata fält:

public class Bankkonto {
    private double saldo;

    public Bankkonto(double startSaldo) {
        this.saldo = startSaldo;
    }

    // Getter — läsåtkomst
    public double getSaldo() {
        return saldo;
    }

    // Setter — skrivåtkomst med validering
    public void insattning(double belopp) {
        if (belopp <= 0) {
            throw new IllegalArgumentException("Belopp måste vara positivt");
        }
        saldo += belopp;
    }

    // En metod istället för setter — mer semantisk
    public void uttag(double belopp) {
        if (belopp <= 0) {
            throw new IllegalArgumentException("Belopp måste vara positivt");
        }
        if (belopp > saldo) {
            throw new RuntimeException("Otillräckligt saldo");
        }
        saldo -= belopp;
    }
}

När ska man använda getters/setters?

Använd getter + setterAnvänd bara getterAnvänd varken (public field)
När du behöver valideraNär fältet är final (oföränderligt)För enkla DTOs / records
När du vill logga åtkomstNär du inte vill att värdet ska ändras utifrånNär du har en enkel databehållare

Immutability — oföränderliga objekt

Ett immutable (oföränderligt) objekt kan inte ändras efter att det skapats. Detta är en extrem form av inkapsling och förebygger hela klasser av buggar.

public final class Person {
    private final String namn;     // final — kan bara sättas en gång
    private final int alder;

    public Person(String namn, int alder) {
        this.namn = namn;
        this.alder = alder;
    }

    // Bara getters — inga setters!
    public String getNamn() { return namn; }
    public int getAlder()   { return alder; }
}

Person p = new Person("Anna", 30);
// p.namn = "Eva";   // GÅR INTE — private final
// p.setNamn("Eva"); // GÅR INTE — ingen setter
// p.alder = 31;     // GÅR INTE — private final

Fördelar med immutability:

  • Trådsäkert — kan delas mellan trådar utan låsning
  • Förutsägbart — ingen kan ändra objektet i efterhand
  • Lätt att cacha och återanvända

Inkapsling på metodnivå

Inkapsling handlar inte bara om fält — även metoder kan vara privata:

public class Tvättmaskin {
    public void startaProgram(String program) {
        lasDorren();
        fyllVatten();
        varmUpp();
        tvatta(program);
        tomVatten();
        centrifugera();
        oppnaDorren();
    }

    // Privata hjälpmetoder — interna detaljer
    private void lasDorren()     { /* ... */ }
    private void fyllVatten()    { /* ... */ }
    private void varmUpp()       { /* ... */ }
    private void tvatta(String p) { /* ... */ }
    private void tomVatten()     { /* ... */ }
    private void centrifugera()  { /* ... */ }
    private void oppnaDorren()   { /* ... */ }
}

Användaren av Tvättmaskin behöver bara veta att startaProgram() finns — de 19 stegen internt är dolda. Detta är abstraktion i praktiken.


Inkapsling i olika språk

SpråkPrivatePublicProtectedNotes
JavaprivatepublicprotectedStandard = package-private
TypeScriptprivatepublicprotectedStandard = public
PHPprivatepublicprotectedStandard = public
C#privatepublicprotectedStandard = private
Python__var (name mangling)var_var (konvention)Inga strikta modifierare

Fortsätt till Arv och Komposition.

Av Victor Hernandez från Bytebase.se