Vanlige designmønstre som Singleton, Observer og Factory.
Oppskrifter du slipper å finne opp på nytt
Mange programmeringsproblemer dukker opp igjen og igjen. I stedet for å finne opp løsningen hver gang, kan vi bruke designmønstre – beprøvde oppskrifter for vanlige utfordringer. Et designmønster er ikke ferdig kode du kan kopiere, men en generell, gjenbrukbar løsning, en mal du tilpasser din egen situasjon.
Hvorfor er de nyttige? De gir utviklere et felles språk, så du kan si «her bruker vi Observer» og bli forstått. De dokumenterer beste praksis, gjør koden mer vedlikeholdbar og fleksibel, og løser kjente problemer effektivt. Designmønstre ble for alvor populære gjennom boken «Design Patterns» fra 1994, skrevet av fire forfattere som kollektivt kalles «Gang of Four».
Vi skal se på tre grunnleggende mønstre. Observer lar objekter varsles automatisk når noe endres. Strategy gjør algoritmer utskiftbare. Factory skjuler hvordan objekter opprettes. Til sammen dekker de tre svært vanlige behov, og du vil møte dem igjen i nesten alle store systemer.
Observer – abonner på endringer
Det første problemet: du vil at flere objekter skal varsles automatisk når noe endres. Løsningen er Observer-mønsteret, der objekter kan «abonnere» på hendelser. Vi har et Subject – den som observeres – med metodene attach for å legge til en observer, detach for å fjerne en, og notify som varsler alle. Hver Observer har en update-metode som kalles når noe skjer:
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
self._observers.append(observer)
def notify(self, data):
for observer in self._observers:
observer.update(data)Et værvarsel illustrerer det fint. En Værstasjon kan være et Subject. Når temperaturen endres, kaller den notify, og alle abonnentene reagerer: et termometerdisplay hjemme og på skolen viser den nye temperaturen, mens et varslingssystem advarer om glatt vei hvis temperaturen er under null. Det fine er løs kobling: Subject trenger ikke vite hvilke konkrete observers som lytter – bare at de har en update-metode. Du kan legge til nye displayer uten å endre værstasjonen. Akkurat dette mønsteret driver GUI-systemer, der en knapp varsler lyttere når den klikkes, og reaktive programmeringsrammeverk.
Strategy – bytt algoritme på sparket
Neste problem: du har flere måter å gjøre noe på, og vil enkelt kunne bytte mellom dem. Løsningen er Strategy-mønsteret, som lar deg definere en familie av algoritmer, pakke hver av dem inn i sin egen klasse, og gjøre dem utskiftbare. Dette er komposisjon i aksjon: i stedet for å arve oppførsel, har objektet en strategi det delegerer til, og strategien kan byttes mens programmet kjører.
Tenk på sortering. En DataSorter får en strategi i konstruktøren, men har også en sett_strategy-metode for å bytte:
class DataSorter:
def __init__(self, strategy):
self._strategy = strategy
def sett_strategy(self, strategy):
self._strategy = strategy
def sorter_data(self, data):
return self._strategy.sorter(data)Du kan starte med en BubbleSortStrategy og bytte til QuickSortStrategy på sparket, uten å endre DataSorter. Et praktisk eksempel er betaling: en Handlekurv kan ha en sett_betalingsmåte-metode og delegere selve betalingen til en strategi – kredittkort, Vipps eller kontant. Vil du legge til en ny betalingsmåte, lager du bare en ny strategi-klasse. Handlekurven røres ikke. Strategy er altså svaret når du trenger å bytte algoritme eller oppførsel under kjøring.
Factory – skjul hvordan objekter blir til
Det tredje mønsteret løser et tredje problem: du vil opprette objekter uten å spesifisere den eksakte klassen, eller du vil skjule kompleks objektoppretting. Løsningen er Factory-mønsteret – en funksjon eller klasse som tar imot parametere og returnerer riktig objekttype.
En enkel dyrefabrikk(dyretype) kan returnere et Hund-, Katt- eller Ku-objekt avhengig av strengen den får inn. Klienten som kaller fabrikken, trenger ikke kjenne til klassene i det hele tatt – den ber bare om «en hund» og får et objekt med en lag_lyd-metode. Skal du legge til et nytt dyr, oppdaterer du bare fabrikken, ikke all koden som bruker den.
En ryddig variant bruker en ordbok som oppslagstabell i stedet for lange if/elif-kjeder. En RapportFabrikk kan ha en statisk metode lag_rapport(format) med en ordbok som kobler «pdf», «excel» og «html» til hver sin rapportklasse:
formater = {"pdf": PDFRapport, "excel": ExcelRapport, "html": HTMLRapport}
rapport_klasse = formater.get(format.lower())
return rapport_klasse()Vil du støtte et nytt format, legger du bare til en linje i ordboken. Hovedfordelen med Factory er altså at den skjuler objektopprettingslogikken og gjør koden lett å utvide.
Oppsummering
Designmønstre er beprøvde, gjenbrukbare løsninger på tilbakevendende problemer – maler, ikke ferdig kode – og de gir utviklere et felles språk. Vi møtte tre av dem. Observer lar objekter abonnere på hendelser og varsles automatisk, med løs kobling slik at subjektet ikke trenger kjenne sine observers; det driver GUI- og hendelsessystemer. Strategy pakker en familie av algoritmer inn i utskiftbare klasser, basert på komposisjon, slik at oppførsel kan byttes under kjøring uten å endre konteksten. Factory skjuler hvordan objekter opprettes og returnerer riktig type ut fra input, gjerne via en ryddig ordbok-oppslagstabell.
Disse mønstrene er grunnpilarer i profesjonell programvareutvikling. I neste kapittel lærer vi UML for å visualisere klasser og mønstre.
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.