🔒 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:
- Forstå hva innkapsling er og hvorfor det er viktig
- Bruke private og public tilgangsmodifikatorer
- Implementere getters og setters for kontrollert tilgang
- Forstå konseptet immutability (uforanderlighet)
- Refaktorere Point-klassen med god innkapsling
- Anvende innkapsling i praktiske eksempler
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?
- 🛡️ Databeskyttelse: Hindrer ulovlig endring av objektets tilstand
- 🔧 Kontroll: Vi kan validere data før det lagres
- 🏗️ Fleksibilitet: Vi kan endre intern implementasjon uten å påvirke ekstern kode
- 🐛 Feilreduksjon: Mindre risiko for feil når data er beskyttet
🔐 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 String navn;
private int alder;
public Person(String navn, int alder) {
this.navn = navn;
this.alder = alder;
}
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;
public String getNavn() {
return navn;
}
public void setNavn(String navn) {
if (navn != null && !navn.trim().isEmpty()) {
this.navn = navn;
}
}
public int getAlder() {
return alder;
}
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
public String getMerke() {
return merke;
}
public int getToppfart() {
return toppfart;
}
public boolean isElektrisk() {
return erElektrisk;
}
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:
- 🔒 Alle felter er
private final
- 🚫 Ingen setter-metoder
- ✅ Kun getter-metoder
- 🏗️ Alle verdier settes i konstruktøren
- 📋 Hvis objektet inneholder mutable objekter, returner kopier
📝 Immutable Point klasse - Eksempel
Her er en immutable versjon av Point-klassen:
public class ImmutablePoint {
private final double x;
private final double y;
public ImmutablePoint(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
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;
}
}
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;
public Point(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
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;
public ImmutablePoint(double x, double y) {
this.x = x;
this.y = y;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
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
Point p1 = new Point(3, 4);
Point p2 = new Point(0, 0);
System.out.println("x: " + p1.getX());
System.out.println("y: " + p1.getY());
p1.setX(5);
p1.setY(6);
double avstand = p1.distanceTo(p2);
System.out.println("Avstand: " + avstand);
🔒 Immutable Point bruk
ImmutablePoint p1 = new ImmutablePoint(3, 4);
ImmutablePoint p2 = new ImmutablePoint(0, 0);
System.out.println("x: " + p1.getX());
System.out.println("y: " + p1.getY());
ImmutablePoint p3 = p1.move(2, 2);
System.out.println("Originalt: " + p1);
System.out.println("Flyttet: " + p3);
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?
public class Student {
public String navn;
public int alder;
}
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;
}
public String getKontonummer() {
return kontonummer;
}
public String getEier() {
return eier;
}
public double getSaldo() {
return saldo;
}
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å:
- ✅ Forklare hva innkapsling er og hvorfor det er viktig
- ✅ Bruke private og public tilgangsmodifikatorer korrekt
- ✅ Implementere getters og setters med validering
- ✅ Lage immutable klasser med final felter
- ✅ Refaktorere klasser for bedre innkapsling
- ✅ Velge mellom mutable og immutable design
🚀 Neste økt: Aggregasjon vs. Komposisjon
🏠 Hjemmeoppgave og videre arbeid
📚 Hjemmeoppgave til neste gang
Del 1: Praktisk koding (45 min)
- 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
- Lag en immutable Adresse klasse:
- Gate, postnummer, by, land
- Final felter
- Kun getters og toString()
- 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.