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:
| Modifierare | Samma klass | Samma paket | Subklass | Alla |
|---|---|---|---|---|
private | Ja | Nej | Nej | Nej |
default (ingen) | Ja | Ja | Nej | Nej |
protected | Ja | Ja | Ja | Nej |
public | Ja | Ja | Ja | Ja |
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 + setter | Använd bara getter | Använd varken (public field) |
|---|---|---|
| När du behöver validera | När fältet är final (oföränderligt) | För enkla DTOs / records |
| När du vill logga åtkomst | När du inte vill att värdet ska ändras utifrån | Nä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åk | Private | Public | Protected | Notes |
|---|---|---|---|---|
| Java | private | public | protected | Standard = package-private |
| TypeScript | private | public | protected | Standard = public |
| PHP | private | public | protected | Standard = public |
| C# | private | public | protected | Standard = private |
| Python | __var (name mangling) | var | _var (konvention) | Inga strikta modifierare |
Fortsätt till Arv och Komposition.
Av Victor Hernandez från Bytebase.se