Tilbake
2.1
Komposisjon og aggregering

2.1 Komposisjon og aggregering

Bygge komplekse objekter med komposisjon.

60 min
6 oppgaver
KomposisjonAggregeringHas-a-relasjon
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 6 oppgaver

Komposisjon og aggregering

Du har lært om arv, der en klasse er en spesialisering av en annen. Men ofte ønsker vi at en klasse har en annen som del av seg selv. Dette kalles komposisjon eller aggregering, og er et kraftig alternativ til arv.

I dette kapittelet skal du lære hvordan du bygger komplekse objekter ved å kombinere enklere objekter, og hvorfor "favor composition over inheritance" er et viktig designprinsipp.

Definisjon
Komposisjon er når ett objekt inneholder ett eller flere andre objekter som en del av sin tilstand. Vi sier at objektet har en relasjon til de andre objektene.

Aggregering er en svakere form for komposisjon der inneholdte objekter kan eksistere uavhengig av container-objektet.

Delegering betyr å overlate ansvar til et innebygget objekt i stedet for å arve oppførsel.

✏️Eksempel

Eksempel: Bil har en motor

I stedet for at Bil arver fra Motor, kan vi la Bil ha en Motor:

class Motor:
    def __init__(self, hestekrefter):
        self.hestekrefter = hestekrefter
        self.kjorer = False

    def start(self):
        self.kjorer = True
        print(f"Motor med {self.hestekrefter} hk startet!")

    def stopp(self):
        self.kjorer = False
        print("Motor stoppet.")

class Bil:
    def __init__(self, merke, hestekrefter):
        self.merke = merke
        self.motor = Motor(hestekrefter)  # Komposisjon!

    def start_bil(self):
        print(f"{self.merke} starter...")
        self.motor.start()  # Delegering

    def stopp_bil(self):
        self.motor.stopp()
        print(f"{self.merke} stoppet.")

# Bruk
min_bil = Bil("Tesla Model 3", 450)
min_bil.start_bil()
# Output:
# Tesla Model 3 starter...
# Motor med 450 hk startet!

Her har Bil en Motor, og delegerer start/stopp-oppgaver til den.

Definisjon
Favor composition over inheritance er et velkjent designprinsipp som sier:

"Foretrekk å bygge funksjonalitet ved å kombinere objekter (komposisjon) fremfor å arve oppførsel (arv)."

Fordeler med komposisjon:
- Mer fleksibel – kan endre oppførsel ved runtime
- Løsere kobling – objekter er mindre avhengige av hverandre
- Enklere testing – kan enkelt bytte ut deler
- Unngår problemer med dyp arvshierarki

✏️Eksempel

Eksempel: Komposisjon vs. arv

Med arv (mindre fleksibelt):

class Flygende:
    def fly(self):
        print("Flyr!")

class Svømmende:
    def svøm(self):
        print("Svømmer!")

class And(Flygende, Svømmende):  # Multippel arv
    pass

# Hva om vi vil ha en and som ikke kan fly?
# Må lage ny klasse...

Med komposisjon (mer fleksibelt):

class FlyOppførsel:
    def utfør(self):
        print("Flyr!")

class SvømOppførsel:
    def utfør(self):
        print("Svømmer!")

class IngenFlyOppførsel:
    def utfør(self):
        print("Kan ikke fly.")

class And:
    def __init__(self, fly_oppførsel, svøm_oppførsel):
        self.fly_oppførsel = fly_oppførsel
        self.svøm_oppførsel = svøm_oppførsel

    def fly(self):
        self.fly_oppførsel.utfør()

    def svøm(self):
        self.svøm_oppførsel.utfør()

# Nå kan vi enkelt lage forskjellige ender:
and1 = And(FlyOppførsel(), SvømOppførsel())
and1.fly()  # Flyr!

and2 = And(IngenFlyOppførsel(), SvømOppførsel())
and2.fly()  # Kan ikke fly.

Med komposisjon kan vi bytte oppførsel uten å lage nye klasser!

✏️Eksempel

Eksempel: Aggregering vs. komposisjon

Komposisjon (tight kobling): Hjerte eksisterer ikke uten person.

class Hjerte:
    def __init__(self, bpm):
        self.hjerteslag_per_minutt = bpm

    def slå(self):
        print(f"Hjerte slår {self.hjerteslag_per_minutt} ganger/min")

class Person:
    def __init__(self, navn):
        self.navn = navn
        self.hjerte = Hjerte(70)  # Lager hjertet her

# Når person slettes, slettes også hjertet

Aggregering (løs kobling): Bil kan ha hjul, men hjul kan eksistere separat.

class Hjul:
    def __init__(self, størrelse):
        self.størrelse = størrelse

class Bil:
    def __init__(self, hjul_liste):
        self.hjul = hjul_liste  # Får hjul utenfra

# Hjul kan eksistere uavhengig av bil
hjul1 = Hjul(18)
hjul2 = Hjul(18)
hjul3 = Hjul(18)
hjul4 = Hjul(18)

min_bil = Bil([hjul1, hjul2, hjul3, hjul4])
# Hjulene eksisterer fortsatt selv om bil slettes

I praksis brukes begge termer ofte om hverandre.

✏️Eksempel

Eksempel: Delegering i praksis

La oss bygge et enkelt Spill-system med komposisjon:

class Grafikk:
    def tegn_skjerm(self, tekst):
        print(f"🎮 {tekst}")

class Lyd:
    def spill_effekt(self, lyd):
        print(f"🔊 {lyd}")

class Inndata:
    def les_tast(self):
        return input("Trykk tast > ")

class Spill:
    def __init__(self):
        self.grafikk = Grafikk()
        self.lyd = Lyd()
        self.inndata = Inndata()
        self.poeng = 0

    def start(self):
        self.grafikk.tegn_skjerm("Spillet starter!")
        self.lyd.spill_effekt("Start-musikk")

        while True:
            kommando = self.inndata.les_tast()

            if kommando == "a":
                self.angrip()
            elif kommando == "q":
                self.avslutt()
                break

    def angrip(self):
        self.grafikk.tegn_skjerm("Du angriper!")
        self.lyd.spill_effekt("Sverd-lyd")
        self.poeng += 10
        print(f"Poeng: {self.poeng}")

    def avslutt(self):
        self.grafikk.tegn_skjerm("Spillet avsluttes...")
        self.lyd.spill_effekt("Avslutt-musikk")

# Bruk
# spill = Spill()
# spill.start()

Spillet har grafikk, lyd og inndata-objekter, og delegerer ansvar til dem.

Oppsummering

I dette kapittelet har du lært:

- Komposisjon betyr at en klasse inneholder objekter av andre klasser ("har-en")
- Aggregering er en svakere form der inneholdte objekter kan eksistere uavhengig
- Delegering er å overlate ansvar til inneholdte objekter
- "Favor composition over inheritance" – foretrekk komposisjon for fleksibilitet
- Komposisjon gir løsere kobling og gjør kode mer vedlikeholdbar

Neste steg: Vi skal bruke komposisjon til å bygge datastrukturer!

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.