1 / 20

🔒 Innkapsling i Objektorientert Programmering

Økt 3: Private/Public, Getters/Setters og Immutability

I denne økten skal vi lære hvordan vi beskytter data i våre klasser og kontrollerer tilgangen til dem.

Klikk på pilene eller bruk piltastene for å navigere

🎯 Læringsmål for denne økten

Etter denne økten skal du kunne:

Innkapsling er en av de fire grunnpilarene i objektorientert programmering!

🤔 Hva er innkapsling?

Innkapsling (encapsulation) er prinsippet om å skjule interne detaljer i en klasse og bare eksponere det som er nødvendig utad.

Tenk på innkapsling som en kapsel:

Private data
og metoder
🔒
Public interface
(getters/setters)
🔓
Ekstern
tilgang
👤

Hvorfor er dette viktig?

🔐 Private vs Public tilgangsmodifikatorer

Tilgangsmodifikator Beskrivelse Tilgang fra Eksempel bruk
private Kun tilgjengelig innenfor samme klasse Kun interne metoder Interne data, hjelpemetoder
public Tilgjengelig fra alle steder Overalt i programmet Konstruktører, getters, setters
public class Person { // Private - kun tilgjengelig innenfor klassen private String navn; private int alder; // Public - tilgjengelig utenfra public Person(String navn, int alder) { this.navn = navn; this.alder = alder; } // Public metode for å få tilgang til private data public String getNavn() { return navn; } }

🧐 Interaktiv øvelse: Hva er galt her?

Se på denne koden og tenk over hvilke problemer du ser:

public class BankKonto { public double saldo; public String kontonummer; public BankKonto(double startSaldo) { saldo = startSaldo; kontonummer = "123456789"; } }

🤔 Klikk her for å se problemene

Problemer med denne koden:

  • saldo er public - hvem som helst kan endre den direkte!
  • kontonummer er public - kan endres utenfra
  • ✗ Ingen validering av startSaldo (kan være negativ)
  • ✗ Ingen kontroll over hvordan data endres

💡 Løsning: Bruk private felter og public metoder for kontrollert tilgang!

🔄 Getters og Setters

Getters og setters er public metoder som gir kontrollert tilgang til private felter:

🔍 Getter

Returnerer verdien av et privat felt

  • Navnkonvensjon: get + Feltnavn
  • For boolean: is + Feltnavn
  • Returnerer alltid en verdi

✏️ Setter

Setter verdien av et privat felt

  • Navnkonvensjon: set + Feltnavn
  • Tar en parameter
  • Kan inneholde validering
public class Person { private String navn; private int alder; // Getter for navn public String getNavn() { return navn; } // Setter for navn med validering public void setNavn(String navn) { if (navn != null && !navn.trim().isEmpty()) { this.navn = navn; } } // Getter for alder public int getAlder() { return alder; } // Setter for alder med validering public void setAlder(int alder) { if (alder >= 0 && alder <= 120) { this.alder = alder; } } }

💻 Praktisk aktivitet: Skriv getters og setters

🎯 Oppgave (10 minutter)

⏱️ 10 min

Du har denne klassen:

public class Bil { private String merke; private int toppfart; private boolean erElektrisk; }

Skriv getters og setters for alle feltene med følgende validering:

  • merke: Ikke null eller tom
  • toppfart: Mellom 50 og 400 km/t
  • erElektrisk: Ingen spesiell validering

💡 Klikk for å se løsningen

// Getters public String getMerke() { return merke; } public int getToppfart() { return toppfart; } public boolean isElektrisk() { return erElektrisk; } // Setters public void setMerke(String merke) { if (merke != null && !merke.trim().isEmpty()) { this.merke = merke; } } public void setToppfart(int toppfart) { if (toppfart >= 50 && toppfart <= 400) { this.toppfart = toppfart; } } public void setElektrisk(boolean erElektrisk) { this.erElektrisk = erElektrisk; }

🔒 Immutability (Uforanderlighet)

Et immutable objekt er et objekt som ikke kan endres etter at det er opprettet.

Sammenligning:

🔄 Mutable (Foranderlig)

Kan endres
Har setters
Risiko for feil

🔒 Immutable (Uforanderlig)

Kan IKKE endres
Ingen setters
Tryggere kode

Hvordan lage immutable objekter:

📝 Immutable Point klasse - Eksempel

Her er en immutable versjon av Point-klassen:

public class ImmutablePoint { // final betyr at verdien ikke kan endres etter konstruktøren private final double x; private final double y; // Konstruktør - eneste stedet verdier kan settes public ImmutablePoint(double x, double y) { this.x = x; this.y = y; } // Kun getters - ingen setters! public double getX() { return x; } public double getY() { return y; } // Metoder som "endrer" objektet returnerer nye objekter public ImmutablePoint move(double deltaX, double deltaY) { return new ImmutablePoint(x + deltaX, y + deltaY); } public double distanceTo(ImmutablePoint other) { double dx = x - other.x; double dy = y - other.y; return Math.sqrt(dx * dx + dy * dy); } }

✅ Fordeler med Immutable objekter

🛡️ Sikkerhet

  • Ingen utilsiktet endring av data
  • Trygg deling mellom tråder
  • Ingen side effects

🐛 Feilreduksjon

  • Lettere å debugge
  • Mindre overraskelser i koden
  • Konsistent tilstand

🧠 Forståelse

  • Enklere å resonnere om
  • Klarere hensikt
  • Lettere testing

⚡ Performance

  • Trygg caching
  • Optimalisering mulig
  • Dele data uten kopiering

🤔 Spørsmål: Når bør du IKKE bruke immutable objekter?

Immutable objekter er ikke alltid best:

  • Hyppige endringer: Hvis du ofte må "endre" objektet (lager mange nye objekter)
  • Minnebruk: Kan bruke mer minne ved mange kopier
  • Performance-kritiske situasjoner: Når objekt-opprettelse er kostbart
  • Store objekter: Med mye data som sjelden endres helt

💡 Regel: Bruk immutable som standard, mutable når du virkelig trenger det!

🔧 Refaktorering: Forbedre Point-klassen

La oss ta den opprinnelige Point-klassen og forbedre den med god innkapsling:

❌ Før (dårlig innkapsling)

public class Point { public double x; public double y; public Point(double x, double y) { this.x = x; this.y = y; } }

Problemer:

  • Public felter
  • Ingen kontrollert tilgang
  • Kan endres direkte

✅ Etter (god innkapsling)

public class Point { private double x; private double y; public Point(double x, double y) { setX(x); setY(y); } public double getX() { return x; } public void setX(double x) { this.x = x; } // Tilsvarende for y... }

Forbedringer:

  • Private felter
  • Kontrollert tilgang
  • Kan legge til validering

🛠️ Hands-on: Refaktorer Point-klassen

🎯 Oppgave (15 minutter)

⏱️ 15 min

Del 1 (5 min): Lag en mutable Point-klasse med god innkapsling

Del 2 (10 min): Lag en immutable versjon av Point-klassen

Krav for begge versjoner:

  • Private felter for x og y koordinater
  • Konstruktør som tar x og y som parametere
  • Getters for x og y
  • En distanceTo(Point other) metode
  • En toString() metode

Ekstra for immutable versjon:

  • Felter skal være final
  • Ingen setters
  • En move(double deltaX, double deltaY) metode som returnerer nytt Point

💡 Løsning: Mutable Point med god innkapsling

public class Point { private double x; private double y; // Konstruktør public Point(double x, double y) { this.x = x; this.y = y; } // Getters public double getX() { return x; } public double getY() { return y; } // Setters public void setX(double x) { this.x = x; } public void setY(double y) { this.y = y; } // Hjelpemetoder public double distanceTo(Point other) { double dx = this.x - other.x; double dy = this.y - other.y; return Math.sqrt(dx * dx + dy * dy); } @Override public String toString() { return "Point(" + x + ", " + y + ")"; } }

💡 Løsning: Immutable Point

public class ImmutablePoint { private final double x; private final double y; // Konstruktør - eneste sted verdier kan settes public ImmutablePoint(double x, double y) { this.x = x; this.y = y; } // Kun getters - ingen setters! public double getX() { return x; } public double getY() { return y; } // "Endring" returnerer nytt objekt public ImmutablePoint move(double deltaX, double deltaY) { return new ImmutablePoint(x + deltaX, y + deltaY); } public double distanceTo(ImmutablePoint other) { double dx = this.x - other.x; double dy = this.y - other.y; return Math.sqrt(dx * dx + dy * dy); } @Override public String toString() { return "ImmutablePoint(" + x + ", " + y + ")"; } }

🚀 Bruk av de refaktorerte Point-klassene

🔄 Mutable Point bruk

// Opprette og bruke mutable point Point p1 = new Point(3, 4); Point p2 = new Point(0, 0); // Få verdier System.out.println("x: " + p1.getX()); System.out.println("y: " + p1.getY()); // Endre verdier p1.setX(5); p1.setY(6); // Beregne avstand double avstand = p1.distanceTo(p2); System.out.println("Avstand: " + avstand);

🔒 Immutable Point bruk

// Opprette immutable points ImmutablePoint p1 = new ImmutablePoint(3, 4); ImmutablePoint p2 = new ImmutablePoint(0, 0); // Få verdier (samme som før) System.out.println("x: " + p1.getX()); System.out.println("y: " + p1.getY()); // "Flytte" punktet (returnerer nytt objekt) ImmutablePoint p3 = p1.move(2, 2); System.out.println("Originalt: " + p1); System.out.println("Flyttet: " + p3); // Beregne avstand double avstand = p1.distanceTo(p2);

🔍 Legg merke til: Immutable versjon gir oss trygghet - vi vet at objektene aldri endres!

📋 Designprinsipper for god innkapsling

✅ Gjør dette

  • Gjør alle felter private som standard
  • Bruk getters/setters for kontrollert tilgang
  • Valider data i setters
  • Vurder immutability når det passer
  • Skjul implementasjonsdetaljer
  • Hold public interface minimal

❌ Unngå dette

  • Public felter (unntatt konstanter)
  • Setters uten validering
  • Eksponering av interne objekter
  • Overekspone funksjoner og kode
  • Komplekse public interfaces
  • Mutating methods på immutable objekter

🧠 Refleksjonsspørsmål: Hvilke av disse klassene har god innkapsling?

// Klasse A public class Student { public String navn; public int alder; } // Klasse B public class Student { private String navn; private int alder; public String getNavn() { return navn; } public void setNavn(String navn) { this.navn = navn; } public int getAlder() { return alder; } public void setAlder(int alder) { this.alder = alder; } }

💡 Svar: Klasse B har bedre innkapsling, men kunne vært enda bedre med validering i setters!

🏦 Case-studie: BankKonto klasse

La oss designe en BankKonto klasse med god innkapsling:

public class BankKonto { private final String kontonummer; private double saldo; private final String eier; public BankKonto(String kontonummer, String eier, double startSaldo) { this.kontonummer = kontonummer; this.eier = eier; this.saldo = startSaldo >= 0 ? startSaldo : 0; } // Getters - trygg tilgang til data public String getKontonummer() { return kontonummer; } public String getEier() { return eier; } public double getSaldo() { return saldo; } // Kontrollerte operasjoner isteden for setters public boolean innskudd(double belop) { if (belop > 0) { saldo += belop; return true; } return false; } public boolean uttak(double belop) { if (belop > 0 && belop <= saldo) { saldo -= belop; return true; } return false; } }

👥 Gruppeaktivitet: Design en klasse

🎯 Oppgave (15 minutter)

⏱️ 15 min

Gruppe på 2-3 personer. Design en klasse for en av disse:

🎮 Spillkort

  • Farge (hjerter, spar, etc.)
  • Verdi (A, 2-10, J, Q, K)
  • Kan ikke endres etter opprettelse

📚 Bok

  • Tittel, forfatter, ISBN
  • Antall sider
  • Er utlånt (true/false)

🚗 Bil

  • Merke, modell, årsmodell
  • Kilometerstand
  • Er i bruk (true/false)

👤 Bruker

  • Brukernavn, e-post
  • Registreringsdato
  • Er aktiv (true/false)

Husk:

  • Bruk private felter
  • Lag passende getters/setters
  • Legg til validering hvor det passer
  • Vurder hvilke felter som bør være immutable
  • Lag minst en hjelpemetode

📝 Oppsummering: Innkapsling

🎯 Hovedpunkter fra dagens økt:

🔒 Innkapsling
Skjule interne detaljer
Kontrollert tilgang
🔐 Private/Public
Private: kun intern tilgang
Public: ekstern tilgang
🔄 Getters/Setters
Kontrollerte metoder
Med validering
🔒 Immutability
Uforanderlige objekter
Final felter

🏆 Du kan nå:

🚀 Neste økt: Aggregasjon vs. Komposisjon

🏠 Hjemmeoppgave og videre arbeid

📚 Hjemmeoppgave til neste gang

Del 1: Praktisk koding (45 min)

  1. Lag en Person klasse med god innkapsling:
    • Private felter: navn, fødselsdato, telefonnummer
    • Getters og setters med validering
    • En metode som beregner alder basert på fødselsdato
  2. Lag en immutable Adresse klasse:
    • Gate, postnummer, by, land
    • Final felter
    • Kun getters og toString()
  3. Test klassene i en main-metode

Del 2: Refleksjon (15 min)

Skriv en kort tekst (150-200 ord) om:

  • Når ville du valgt mutable vs immutable design?
  • Hvilke fordeler ser du med god innkapsling?
  • Gi et eksempel fra virkeligheten hvor innkapsling er viktig

💡 Tips: Tenk på innkapsling som "information hiding" - vis bare det som er nødvendig!

📧 Spørsmål? Send e-post eller kom på kontoret før neste time.