objektorientering 2
TRANSCRIPT
Opphavsrett: Forfatter og Stiftelsen TISIP
Avdeling for informatikk og e-læring, Høgskolen i Sør-Trøndelag
Objektorientering i VB – videregående Oppdatert av Atle Nes
Objektorientering i VB – videregående Resymé: Denne leksjonen tar opp flere detaljer knyttet til bruk av klasser. Et av de viktigste prinsippene innen
objektorientering, er innkapsling. Hva er det, og hvordan gjøres det i praksis?
10.1. PROBLEMATIKKEN KNYTTET TIL INNKAPSLING ....................................................................................... 2 10.1.1. Eksempel på bruk av Public objektvariabler ................................................................................. 2 10.1.2. Public objektvariabler er ikke god programmeringsskikk ............................................................. 3
10.2. MULIG TILNÆRMING NR 1 – OFFENTLIGE METODER ............................................................................... 4 10.2.1. Egen metode for å sette objektvariabler ........................................................................................ 4 10.2.2. Forklaring til metoden lagreInformasjon() .................................................................................... 5 10.2.3. Bruk av metoden lagreInformasjon() ............................................................................................. 5 10.2.4. Bruk av mange metoder for å lagre og hente informasjon ............................................................ 7 10.2.5. Metoder kan gjøre det du vil – også validering ............................................................................. 8 10.2.6. Oppsummert: Hvorfor metoder? .................................................................................................. 10
10.3. MULIG TILNÆRMING NR 2 – KONSTRUKTØRER ..................................................................................... 10 10.3.1. Hva skjer når vi lager et nytt objekt? ........................................................................................... 10 10.3.2. Konstruktører lager og fyller objektet på en gang ....................................................................... 11 10.3.3. En enda kortere syntaks ............................................................................................................... 12 10.3.4. Overloading ................................................................................................................................. 13
10.4. MULIG TILNÆRMING NR 3 – BRUK AV PROPERTY ................................................................................. 14 10.4.1. Property brukes primært til å hente og endre verdi i objektvariabler ......................................... 14 10.4.2. Forklaring til Get og Set .............................................................................................................. 15 10.4.3. Detaljer og ytterligere forklaring ................................................................................................ 16 10.4.4. Hva har en skarve TextBox og en Label å gjøre med en Aha-opplevelse? .................................. 16 10.4.5. En siste Aha-opplevelse ............................................................................................................... 18
Objektorientering i VB – videregående side 2 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
10.1. Problematikken knyttet til innkapsling
Vi så i leksjonen om grunnleggende objektorientering, at en klasse har objektvariabler
(egenskaper) og metoder. Et eksempel på en klasse er Person, og denne personen har kanskje
en vekt, et navn og en høyde. Det er mulig å finne en såkalt ”body mass index” til personen
basert på en utregning av vekt deltpå høyden (i meter) opphøyd i andre. I stedet for å
registrere body mass index, passer det å lage en metode som regner denne ut ved behov.
Basisinformasjon om vekt og høyde kan også brukes til mye annet rart.
Vi skal nå se hvordan vi kan gjøre koden vår mer modulær og selvstendig. Dette er et ønske
innen objektorientering.
10.1.1. Eksempel på bruk av Public objektvariabler
Dersom vi ikke tar med noen metoder, vil klassen Person kunne se slik ut:
Public Class Person
Public navn As String 'navnet på personen
Public vekt As Double 'antall kg
Public hoyde As Double 'antall cm
'Tar ikke med noen metoder her for oversiktens skyld
End Class
Husk at en klasse gjerne ligger i en egen fil, og uansett mellom kodeordene Public
Class KlassensNavn og End Class. Siden vi har angitt kodeordet Public foran
objektvariablene navn, vekt og hoyde, vil disse objektvariablene kunne brukes utenfor filen
(faktisk også på tvers av prosjekter om en vil det, så lenge prosjektene ligger i samme
solution). Det betyr at vi kan skrive følgende under for eksempel Button1 i Form1:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'Lager en ny instans av klassen Person
Dim lise As Person
lise = New Person
'Registrerer navn, høyde og vekt for Lise
lise.vekt = 62
lise.navn = "Lise Nordmann"
lise.hoyde = 170
MsgBox(lise.navn & " er " & lise.hoyde & " høy")
End Sub
Her har vi laget et nytt objekt som heter lise. Lise må ha en alder, et navn og en høyde. Det
er nødvendig å fylle objektet lise sine objektvariabler med informasjon. Etter å ha gjort dette,
henter vi ut informasjon om objektet (navn og høyde) og skriver ut i en meldingsboks.
Objektorientering i VB – videregående side 3 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Figur 1: Objektet lise (til høyre) som er en instans av den generelle klassen Person (til venstre).
10.1.2. Public objektvariabler er ikke god programmeringsskikk
Vi kan bruke punktumnotasjonen objekt.objektvariabel = "verdi" for å foreta
en tilordning til en objektvariabel. Dette fungerer i vårt eksempel ene og alene fordi vi har satt
Public foran navnet på objektvariablene i klassen Person. Dersom vi hadde satt Dim
navn As String, så ville det ikke fungert å skrive lise.navn = "Lise
Nordmann" under Button1_Click. Dim er en såkalt modifikator som angir en lokal
variabel, mens Public altså er en modifikator som gjør at en variabel (eller en klasse eller en
metode/funksjon) blir tilgjengelig overalt.
Her er et interessant apropos for den som er interessert. Private er nemlig en
mellomting mellom Public og Dim. Private betyr dermed at variabelen er tilgjengelig
overalt innenfor klassen, men ikke utenfor. Det var forresten slik vi kunne lage globale
variabler, matriser og funksjoner tidligere i kurset. Vi satte da kodeordet Private foran globale
variabler, for eksempel slik: Private matrise(4) as Integer. Vi plasserte slike
globale ting øverst i koden, før alle knappene våre. Den observante leser har trolig sett at det i
alle programmer vi har laget til nå i hele kurset, helt øverst har stått Public Class
Form1, og helt nederst har stått en tilsvarende End Class. Det vil si at når vi lager en
knapp ved å dobbeltklikke på koden til Form1, så er vi egentlig bare kommet til koden som
angir klassen Form1... Alt av kode til knappene våre etc. ligger i denne klassen, og dermed vil
Private-variabler få en global funksjon.
Så tilbake til problemstillingen: Vi kan deklarere objektvariablene som Public, og vi får da
tilgang til å endre og sette disse fra utsiden. Det er derimot noen ulemper med en slik
fremgangsmåte:
Dersom vi senere ønsker å endre klassens objektvariabler til å hete noe annet, for
eksempel ikke ”navn”, men ”fornavn”, så betyr det at vi må endre koden også i
Button1_Click. Klassen har plutselig en mindre smart avhengighet til der hvor
objektene brukes i praksis.
Validering av data overlates til den som programmerer objektene, ikke den som har
programmert klassen. Dersom noen forsøker å lage et nytt personobjekt og gi en
feilaktig verdi, som vist her, vil programmet kræsje siden klassen forventer en Double-
verdi:
Dim kari as Person
kari = New Person
kari.vekt = "vet ikke" 'her kræsjer programmet fordi datatypen er feil
!
Objektorientering i VB – videregående side 4 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Generelt gjelder prinsippet innen objektorientering at en skal forsøke å innkapsle koden.
Klassen Person beskriver karakteristika og aksjoner som gjelder for en generell person. Det er
om å gjøre å holde dette så generelt som mulig. En bør derfor unngå å kreve at objektvariabler
refereres til direkte fra koden der hvor objektene lages og brukes.
Likevel er det selvsagt nødvendig å si at for eksempel Ole er 83 kg og 192 cm. Hvis ikke, kan
vi ikke finne ut hva Ole sin ”body mass index” er, og vi kan heller ikke gjøre noe annet
fornuftig med Ole. Det er altså essensielt å kunne endre objektvariablene til et objekt, uten å
måtte bruke Public-variabler i klassens kode. Hvordan får vi til dette?
Figur 2: Ønsker at koden i for eksempel Button1_Click skal ha mulighet til å få lagret informasjon inn i objektet ”ole”, uten å bryte med prinspper rundt innkapsling.
10.2. Mulig tilnærming nr 1 – offentlige metoder
En klasse kan ha objektvariabler og metoder. I stedet for å bruke Public objektvariabler, og
sette disse der objektene brukes ved hjelp av ole.vekt = 83, kan vi jo lage lages en
metode som får i oppdrag å sette Ole sin vekt. Metoder skal vanligvis kunne kalles opp
utenfra klassen, og disse er derfor stort sett deklarert som Public. Selve metoden ligger inne i
klassen, og det betyr at den har tilgang til alle Private-variabler. Det betyr at vi kan lage oss en
Public-metode, og la den få i oppdrag å registrere verdier i objektvariablene!
10.2.1. Egen metode for å sette objektvariabler
La oss nå lage en ny, modifisert og bedre utgave av klassen Person:
Public Class Person
Private navn As String 'objektvariablene er kun tilgjengelige
Private vekt As Double 'internt i denne klassen
Private hoyde As Double 'siden de er deklarert som Private
Public Sub lagreInformasjon(ByVal navn As String, _
ByVal kg As Double, _
ByVal cm As Double)
'Metode for å registrere data om navn, vekt og høyde.
'Fyller objektvariablene med innholdet som kommer fra argumentene
vekt = kg 'argumentet heter "kg" mens objektvariabelen heter "vekt"
hoyde = cm
Me.navn = navn
'dersom argumentet og objektvariabelen heter det samme,
'må kodeordet Me. brukes for å angi objektvariabelen
End Sub
End Class
Objektorientering i VB – videregående side 5 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Her har vi laget en metode som har én eneste oppgave i livet:
Motta informasjon om et navn, en vekt og en høyde.
Plassere denne informasjonen inn i dette objektets tilsvarende objektvariabler.
10.2.2. Forklaring til metoden lagreInformasjon()
Det er noen detaljer som bør forklares i koden til metoden lagreInformasjon()
Vi har brukt kodeordet Sub, siden dette er en metode som ikke skal returnere noen
verdi. Vi kunne brukt Function, men da skal vi egentlig returnere en verdi, og det
er ikke nødvendig her, så da bruker vi helst Sub.
Metoden har tre argumenter. Disse heter navn, kg og cm. Dette er på en måte
inngangsporten for informasjon som skal inn til metoden og behandles der inne. Hvis
alt er på en laaaaang linje, så går det greit. Dersom du vil bryte på flere linjer, må
understrek-tegnet brukes (som vi har gjort).
Figur 3: Visual Studio hjelper til ved bruk av metoder. Her vises hvilke argumenter (og datatyper) som må fylles ut.
Det metoden skal gjøre, er å plassere informasjonen som kommer fra hvert av
argumentene inn i riktig objektvariabel. Objektvariabelen vekt skal få den verdien
som sendes gjennom argumentet kg. Objektvariabelen hoyde skal få den verdien
som sendes gjennom argumentet cm.
Merk at objektvariabelen navn skal få den verdien som sendes inn gjennom
argumentet navn. Problemet er at begge heter ”navn”. Her har vi en situasjon som
må håndteres. Hvordan skal VB vite hva som er argumentet, og hva som er
objektvariabel i den koden som kommer inne i selve metoden? Måten å skille dem fra
hverandre på, er å bruke kodeordet Me og et punktum foran objektvariabelen. ”Me”
er nemlig et kodeord som henspeiler tilbake på akkurat dette objektet. Hvorfor brukes
Me. kun i den siste setningen? Fordi de andre to argumentene ikke har samme navn
som objektvariablene, og derfor er det ingen konflikt ute og går. Hva skal en så bruke?
Dette er helt valgfritt. I stedet for å pønske ut synonymer av objektvariablene som
navn på argumentene, kan en med fordel bruke Me. Det er egentlig en smakssak, men
Me er såpass vanlig at du bør kjenne til muligheten slik at du forstår andres kode.
Det siste som er verdt å merke seg, er at denne metoden er deklarert som Public. Det er
veldig viktig, og betyr at den kan kalles opp fra et helt annet sted, for eksempel under
Button1_Click i Form1. Det er nettopp dette vi ønsker. Public er helt nødvendig å
bruke for å angi korrekt tilgang til denne metoden.
10.2.3. Bruk av metoden lagreInformasjon()
La oss nå se hvordan metoden lagreInformasjon() kan brukes i praksis. Vi har her
ganske enkelt dobbeltklikket på en knapp i Form1, og kommer da til koden bak
Objektorientering i VB – videregående side 6 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Button1_Click(...). Vi oppretter to objekter for å tydeliggjøre at hvert objekt er
uavhengig av hverandre (forskjellige instanser av samme klasse).
Public Class Form1
'Program som bruker klassen Person og lager to personer
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'Lager to objektvariabler av type Person
Dim lise As Person
lise = New Person
Dim ole As Person
ole = New Person
'Registrerer navn, vekt og høyde for Ole
ole.lagreInformasjon("Ole Nordmann", 83, 192)
'Registrerer navn, vekt og høyde for Lise
lise.lagreInformasjon("Lise Nordmann", 62, 170)
End Sub
End Class
Legg merke til forskjellen på hvordan objektvariablene navn, vekt og hoyde får innhold denne
gangen, sammenliknet med tidligere. Vi ønsker å registrere objektet ole sitt navn, vekt og
høyde. Vi har ikke tilgang til objektvariablene som ligger inne i objektet, siden disse er lokale
(deklarert med Private). Vi har derimot en metode som kan gjøre jobben for oss, og kaller
derfor opp lagreInformasjon() med de riktige verdiene som argumenter.
Figur 4: Illustrasjon over dataflyten når Public-metoden lagreInformasjon() kalles opp i Button1_Click. Tenk over at objektet er en instans av klassen Person. Objektvariablene er
Objektorientering i VB – videregående side 7 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Private, men siden metoden ligger i samme klasse, har den tilgang til å skrive til objektvariablene.
Det at objektvariabler gjerne deklareres i klassen som Private, mens metoder deklareres
som Public, er veldig ofte tilfelle innen OOP-løsninger. Objektets variabler blir da lokale,
og eksponeres ikke noe annet sted enn internt i objektet. Metodene blir derimot offentlige, og
eksponeres utenfor objektet. Det betyr at vi kan lage metoder som lar oss – fra utsiden – hente
ut eller endre den tilsynelatende utilgjengelige informasjonen i objektvariablene. Dette
prinsippet er viktig å forstå. Ikke fall for fristelsen å plassere Public overalt bare for at det
fungerer. Det vil skape problemer i lengden. Prøv heller å forstå betydningen av disse
modifikatorene først som sist.
10.2.4. Bruk av mange metoder for å lagre og hente informasjon
Vi har nå sett på hvordan vi kan lage en metode for å registrere informasjon i et objekt (i
objektvariablene). Vår metode registrerte informasjon i tre objektvvariabler i samme sleng.
Det er ingenting i veien for å ha flere metoder som registrerer informasjon. Vi kunne
tilsvarende hatt metoder for å lese ut verdien av objektvariablene. Om vi følger en slik
kodestil, vil vi få dobbelt så mange metoder som antall private objektvariabler (altså 6 i vårt
tilfelle).
Public Class Person
Private navn As String 'objektvariablene er kun tilgjengelige
Private vekt As Double 'internt i denne klassen
Private hoyde As Double 'siden de er deklarert som Private
Public Sub lagreNavn(ByVal navn As String)
'Metode for å registrere navnet i riktig objektvariabel
Me.navn = navn
End Sub
Public Sub lagreVekt(ByVal vekt As Double)
Me.vekt = vekt
End Sub
Public Sub lagreHoyde(ByVal hoyde As Double)
Me.hoyde = hoyde
End Sub
Public Function hentNavn() as String
return navn
End Function
Public Function hentVekt() as Double
return vekt
End Function
Public Function hentHoyde() as Double
return hoyde
End Function
End Class
Legg merke til hvordan de tre første metodene er deklarert som Sub. Disse skal lagre det
som kommer inn i argumentet i riktig objektvariabel. De tre siste metodene er derimot
deklarert som Function. Disse skal returnere verdien til de ulike objektvariablene. Legg
Objektorientering i VB – videregående side 8 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
merke til at returtypen for hver metode er satt til det samme som typen på tilhørende
objektvariabel.
Figur 5 viser eksempel på kode som bruker av disse 6 metodene til å lagre og lese
informasjonen i objektvariablene:
Figur 5: Kode bak Button2_Click bruker metoder som er definert i klassen, til å lagre informasjon i objektet ”knut” og hente ut informasjon fra objektet ”knut”.
10.2.5. Metoder kan gjøre det du vil – også validering
Nå tenker du kanskje: ”Dette er jo veldig tungvindt. Hvorfor bruke OOP når det blir så utrolig
mye mer kode å skrive, og så mange ting å holde orden på?”
Fordelene med OOP er mange. Joda, det er riktig at det kan bli mye kode for å løse et lite
problem, men det blir faktisk motsatt (mye mindre kode) når du skal løse større problemer. I
tillegg vil du oppleve gevinster som går på sikkerhet, modularitet, gjenbrukbarhet og
liknende. Du vil kunne bli mer en komponent-programmerer enn en detalj-programmerer. Det
øker mulighetene for bedre produktivitet, effektivitet, kvalitet, sikkerhet og så videre.
Med så mye kode å skrive (to metoder for hver objektvariabel som er Private) kan det være
fristende å lage objektvariablene som Public og slik spare plass. La oss gå gjennom et
eksempel som tar opp et viktig motargument mot å gjøre det så lett som mulig.
Tenk deg at du i knappen Button3_Click i Form1 ønsker å opprette et nytt objekt.
Det er personen Karl Anton det er snakk om. Du lager objektet ka og vil så registrere
høyden på ka. Du skriver inn 1.80 i koden fordi Karl Anton er 1 meter og 80 cm høy.
Problemet er bare at objektvariabelen hoyde bør ha høyden i antall cm. Hvorfor? Fordi
metoden finnBMI() som brukes til å regne ut ”body mass index” (BMI) forventer at
høyden som er lagret i objektet, er oppgitt i antall cm. Denne metoden tar nemlig høyden og
deler på 100. Dersom du ved en feiltakelse registrerer høyden som antall meter i stedet for
antall centimeter, blir det feil å dele på 100 i metoden.
Objektorientering i VB – videregående side 9 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Figur 6: Metoden finnBMI() tar antall cm og deler på 100, før den regner ut BMI.
Denne situasjonen er skummel. Objektvariabelen hoyde er av type Double, så det går
bra å registrere både 180 og 1.80. Hvis en registrerer 180, vil alt gå bra i det en kaller opp
metoden finnBMI(). Hvis en registrerer 1.80, vil finnBMI() klare å regne ut en BMI,
men verdien vil være veldig feil.
Vi kan skrive om metoden til å ikke dele på 100, men da har vi akkurat samme situasjon: en
person som glemmer seg og skriver 180 i stedet for 1.80, vil da oppleve feilen.
Det som er lurt her, er å validere at verdien er riktig før objektvariabelen får innhold. Vi kan
validere på to steder:
I Button3_Click rett før metoden kalles opp. Vi kaller bare opp metoden dersom tallet
er riktig skrevet inn. Dette får vi til med en If-test.
I Klassen Person, nærmere bestemt i metoden lagreHoyde(). Dette får vi til med
en If-test.
La oss nå se hvordan vi kan faktisk tillate brukeren å skrive enten antall meter eller antall
centimeter!
Public Class Person
Private navn As String 'objektvariablene er kun tilgjengelige
Private vekt As Double 'internt i denne klassen
Private hoyde As Double 'siden de er deklarert som Private
'De andre metodene er fjernet her for oversiktens skyld.
Public Sub lagreHoyde(ByVal hoyde As Double)
'Antar at meter brukes hvis tallet er lite
If hoyde < 10 Then
Me.hoyde = hoyde * 100
Else
Me.hoyde = hoyde 'Hvis stort tall, så lagres tallet direkte
End If
End Sub
End Class
Dersom vi nå kaller opp metoden slik:
Dim ka As New Person
ka.lagreHoyde(1.80)
ka.lagreVekt(78)
MsgBox("BMI-verdien til Karl Anton er " & ka.finnBMI())
Objektorientering i VB – videregående side 10 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
så vil resultatet bli at BMI-verdien er ca. 24,07. Dersom vi kaller med
ka.lagreHoyde(180) så får vi samme resultat. Hvis vi ikke hadde foretatt validering,
ville verdien blitt ca 240740, altså et helt feil tall (regn ut selv om du er i tvil).
10.2.6. Oppsummert: Hvorfor metoder?
Fordelen med metode-fremgangsmåten blir åpenbar i følgende scenario:
1. Du har først en metode som setter vekt direkte
2. Du lager et program med mange knapper i mange forms. Rundt om kring i disse har
du behov for å lage nye personer, for eksempel ”Petra” og ”Trulte”. Du oppretter
typisk petra og kaller opp metoden petra.lagreVekt(100) for å få
plassert inn riktig vekt i objektvariabelen til objektet petra. Du skal så lagre for
objektet trulte, og skriver trulte.lagreVekt(859). Du skulle egentlig
skrive 85.9 men, glemte kommaet (punktumet).
3. Du oppdager feilen med en gang, og tenker at ”jeg kan jo rette opp til å være 85.9,
men hva om jeg gjør samme feil senere? La meg heller fikse metoden lagreVekt() til å
ta hensyn til potensielt feil registrering.
4. Du åpner filen som har klassen Person, og lokaliserer metoden lagreVekt(). Du legger
til en If-test inne i den, og vips, så har du fikset alle fremtidige feiltastinger.
5. Det fine med denne fiksen, er at du ikke trenger å endre noe annet sted enn i metoden.
Der metoden kalles fra (i ulike knapper i ulike forms) har en hele tiden antatt at ting
fungerer, uten å bry seg med detaljene i koden bak klassens metode.
Det er nettopp dette OOP handler om – å skjule detaljene. Dersom du fikser detaljene, så skal
det helst ikke gi konsekvenser for resten av programmet der klassen instansieres i form av
objekter. Du får altså økt fleksibilitet ved å la metoder sette verdiene i objektvariablene, i
stedet for å sette verdiene direkte ved å la objektvariablene være offentlige (Public).
10.3. Mulig tilnærming nr 2 – Konstruktører
Det er vanlig å bruke konstruktører for å innkapsle objektvariablene. Konstruktører gjør det
enkelt for oss å opprette et nytt objekt av en klasse (instans) og fylle dette objektet med
innhold på samme tid. Det er mulig å ha flere konstruktører for hver klasse. La oss se
nærmere på hva en konstruktør er, og motivasjonen bak.
10.3.1. Hva skjer når vi lager et nytt objekt?
Når vi skal lage et nytt objekt, bruker vi kodeordet New. Vi kan for eksempel skrive slik:
Dim elisabeth as Person
elisabeth = New Person
I første setning lager vi en liten boks i minnet som kan inneholde adresen til et objekt av type
Person. I andre setning lager vi et nytt objekt, og lagrer referansen til dette objektet i ”boksen”
som heter elisabeth. I stedet for å si at elisabeth nå er ”boksen med referansen som
henviser til objektet elisabeth”, sier vi kort og godt at elisabeth er ”objektet elisabeth”.
Det er mye enklere å snakke om objekter direkte, selv om det egentlig bare er en referanse til
objektet vi snakker om. Den øverste delen av Figur 7 viser et objekt slik vi normalt tenker på
det, mens den nederste delen viser hvordan dette objektet egentlig er representert i minnet i
Objektorientering i VB – videregående side 11 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
maskinen: Boksen som heter elisabeth (og som vi for enkelhetsskyld kaller objektet
elisabeth) har en verdi (referanse) som viser til det stedet i minnet hvor objektet befinner seg.
Figur 7: Objektet elisabeth slik vi kan visualisere oss det (gul figur, øverst) og slik det faktisk representeres inne i maskinen (blå, nederst). 8F6H4003 er adressen til det stedet i minnet hvor objektet ligger lagret.
Når vi oppretter et objekt får vi en kopi av den tilhørende klassen. I Figur 7 vises hvordan et
nytt objekt har de tre objektvariablene vekt, navn og hoyde, men at disse mangler innhold.
Det neste logiske steget er som regel å fylle objektet med innhold. Veldig ofte er nettopp dette
steg 2 noe vi ønsker å gjøre rett etter å ha opprettet objektet.
Kodeordet New kan brukes til å lage et objekt, og så kan vi for eksempel gi objektvariablene
verdier ved å kalle opp respektive metoder. Hva om vi kunne slå sammen disse to
operasjonene til én?
10.3.2. Konstruktører lager og fyller objektet på en gang
Når vi lager et objekt, så kan vi si at vi konstruerer objektet (engelsk: to construct an object).
Innen OOP har vi en spesiell type metode som heter konstruktør (engelsk: constructor).
Denne har i Visual Basic alltid navnet New, og kan deklareres slik i klassen vår:
Public Class Person
Private navn As String 'objektvariablene er kun tilgjengelige
Private vekt As Double 'internt i denne klassen
Private hoyde As Double 'siden de er deklarert som Private
'Her er en Constructor for å registrere en ny person
Public Sub New(ByVal etNavn As String, _
ByVal enVekt As Double, _
ByVal enHoyde As Double)
navn = etNavn
vekt = enVekt
hoyde = enHoyde
End Sub
Objektorientering i VB – videregående side 12 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Public Function finnBMI() As Double 'Regner her ut body mass index
Dim meter As Double
meter = hoyde / 100 'fordi vi skal regne i antall meter, ikke i cm
Return vekt/(meter*meter) 'parentesene regnes ut først
End Function
End Class
Konstruktøren er deklarert som Public, og den kan dermed kalles utenfor klassen. Siden
konsturktøren befinner seg inne i klassen, har den tilgang til alle objektvariablene som er
deklarert med Private. La oss se på bruken av konstruktøren før vi forklarer fullstendig
ferdig :
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'Lager et objekt av type Person
Dim bmi As Double
Dim alex As Person
alex = New Person("Aleksander", 100, 200)
'Skriver ut verdien i objektvariabelen vekt vha Property Vekten
bmi = alex.finnBMI()
MsgBox("BMI-en er: " & bmi)
End Sub
Vi lager et objekt (alex) og setter:
alex = New Person("Aleksander", 100, 200)
Siden vi nå har en konstruktør for klassen som krever 3 argumenter, angir vi 3
argumentverdier i dette kallet. Dermed sendes det 3 argumenter inn til konstruktøren som
definert med New i klassen Person. Se nå tilbake på koden for konstruktøren, og du ser at
det som mottas heter henholdsvis etNavn, enVekt og enHoyde. Disse har nå
henholdsvis verdiene ”Aleksander”, 100 og 200. For å få ”Aleksander” inn i objektvariabelen
navn, skriver vi bare
navn = etNavn
inne i konstruktøren. Tilsvarende fylles de andre objektvariablene med riktige verdier. Nå har
vi i praksis et objekt som ser slik ut:
Figur 8: Etter at konstruktøren er benyttet, har objektet fått en rekke verdier.
10.3.3. En enda kortere syntaks
Det er mulig å skrive enda mer kompakt når vi lager objekter, enn å måtte bruke to linjer. I
stedet for:
Dim alex As Person
Objektorientering i VB – videregående side 13 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
alex = New Person("Aleksander", 100, 200)
kan vi skrive
Dim alex As New Person("Aleksander", 100, 200)
Dermed er det mulig å lage virtuelle utgaver av alle sine slektninger på kort tid, som vist i
Button2_Click her:
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
Dim alex As New Person("Aleksander", 100, 200)
Dim jeppe As New Person("Jens Peder", 78, 190)
Dim kanin As New Person("Kari Nina", 52, 167)
Dim ole As New Person("Ole Bernt Kånrad", 124.78, 197.50)
Dim berith As New Person("Berit Hjørdis", 60.25, 170)
Dim leffen As New Person("Leif Espen", 59, 156)
End Sub
Vi kunne nå funnet BMI på hver enkelt av disse, hvis ønskelig. Du ser at ved bruk av
konstruktører får vi laget objekter og fylt disse med innhold på en rask måte. Dessuten sikrer
vi oss at vi ikke glemmer å registrere objektvariablene. Konstruktører er bra å bruke.
10.3.4. Overloading
Helt til slutt nevnes et begrep som heter overloading (på engelsk). Du har tidligere sett at
metoder kan ha så mange argumenter du selv måtte ønske. Nå har vi nettopp laget en
konstruktør som fyller inn navn, vekt og høyde på en person. Hva om vi ønsker å lage et
objekt som bare har noen standardverdier, for eksempel Ola Nordmann som navn, 85 kg som
vekt og 180 som høyde? Vi kan enkelt lage en konstruktør som gjør dette:
Public Sub New()
navn = "Ola Nordmann"
vekt = 85
hoyde = 180
End Sub
Det fine er at denne konstruktøren kan leve side om side med den første konstruktøren vi
lagde. Vi kan altså ha flere konstruktører i en og samme klasse! Dette er en fin mulighet, og
det øker fleksibiliteten.
Figur 9 og Figur 10 viser eksempel på opprettelse av et nytt objekt (i for eksempel
Button1_Click) basert på klassen Person. I det vi skriver Person( hjelper
utviklingsmiljøet oss og avslører at det fins to tilgjengelige konstruktører. Disse vises i form
av en liste, og vi kan se argumentene og datatypene som forventes for hver konstruktør.
Figur 9: Utviklingsmiljøet hjelper oss og antyder at den første konstruktøren krever tre argumenter.
Objektorientering i VB – videregående side 14 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Figur 10: Utviklingsmiljøet viser den andre konstruktøren når vi trykker pil ned. Den andre krever ingen argumenter.
Det er vanlig at ferdiglagde .NET-klasser har mange konstruktører som en kan velge mellom.
Det er alltid lurt å lese argument-listen for å få en indikasjon av hva som kan gjøres.
Begge formene er mulige å bruke:
Dim svend as New Person("Svend", 88, 196)
Dim ola as New Person()
Som følge av den første linjen, opprettes objektet svend, og det får objektvariablene fylt med
”Svend”, 88 og 196. Den andre linjen lager et objekt som heter ola, og dette får verdiene ”Ola
Nordmann”, 85 og 180. Dette fenomenet – at vi kan ha potensielt mange konstruktører –
gjelder mer generelt også. Det er nemlig mulig å lage metoder som har samme navn, så lenge
antall argumenter varierer. Vi skal ikke gå nærmere inn på dette.
Et lite apropos: Egentlig trenger en ikke skrive parenteser etter Person i den siste linjen. VB
tillater både med og uten parentes dersom argumentlisten er tom.
10.4. Mulig tilnærming nr 3 – bruk av Property
Det er flott å kunne bruke metoder for å lagre informasjon i en objektvariabel, og for å hente
ut informasjon fra en objektvariabel. Det er derimot litt mer tungvindt å måtte kalle en metode
enn å kunne bruke syntaksen som vist aller først i denne leksjonen:
knut.vekt = 76
Den gode nyheten er at det faktisk er mulig å skrive på denne måten, og samtidig beholde
objektvariablene med modifikatoren Private.
10.4.1. Property brukes primært til å hente og endre verdi i objektvariabler
Det fins en spesiell konstruksjon som vi kaller Property som gjør det mulig å fortsatt å ha
objektvariabler som er beskyttet inne i klassen, og samtidig tilby en enkel syntaks for å endre
eller lese verdiene. En Property er en slags metode, men en metode med en veldig spesiell
syntaks. Den brukes i de fleste objektorienterte programmeringsspråk. Strukturen ser slik ut
og skrives inn i klassen:
Public Class Person
Private navn As String 'objektvariablene er kun tilgjengelige
Private vekt As Double 'internt i denne klassen
Private hoyde As Double 'siden de er deklarert som Private
Public Property Vekten() As Double
Get
'Kode du måtte ønske her, typisk
Return vekt
End Get
Set(ByVal value As Double)
'Kode du måtte ønske her, typisk
vekt = value
End Set
Objektorientering i VB – videregående side 15 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
End Property
'Eventuelt flere Property-strukturer og metoder her...
'...
'...
End Class
En Property kan brukes i stedet for metoder som for eksempel lagreHoyde() og hentHoyde().
Det er nødvendig å se på bruken av Property-en før vi kan forklare forskjellen på Get og Set.
Gitt følgende kode i Button1_Click:
'Demonstrerer bruk av Property
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
'Lager et objekt av type Person
Dim jens As Person
jens = New Person
'Registrerer en verdi i objektvariabelen vekt vha Property Vekten
jens.Vekten = 97
'Skriver ut verdien i objektvariabelen vekt vha Property Vekten
MsgBox(jens.Vekten)
End Sub
10.4.2. Forklaring til Get og Set
Det som står mellom Get og End Get aktiveres ganske enkelt når vi i knappen
Button1_Click (eller liknende) skriver
MsgBox(jens.Vekten)
Når vi skriver på syntaksen objekt.Propertynavn, så ønsker vi typisk å hente ut
verdien. Siden Property-strukturen Vekten() egentlig er en slags metode, kan vi bruke
kodeordet Return for å returnere en verdi. Det kan være forvirrende at Property-en ikke
skrives på samme måte som vanlige funksjoner og metoder når den kalles opp, men det er noe
du bare må akseptere. Det som nå er viktig å huske på, er at objektvariabelen vekt er
deklarert som Private i klassen. Det betyr at vekt ikke kan hentes utenfor klassen, men den
kan derimot hentes av alle metoder inne i klassen. Dette inkluderer vår Property som heter
Vekten(). Dermed kan vi skrive setningen Return vekt for å sikre at når en i for
eksempel Button1_Click skriver inn MsgBox(jens.Vekten), så vil kompilatoren
aktivere objektet jens sin Property som heter Vekten() og returnere innholdet i
objektvariabelen vekt. Dermed står det i praksis MsgBox(97), slik at 97 skrives ut.
Det som står mellom Set og End Set aktiveres når vi skriver
jens.Vekten = 97
Tallet bak likhetstegnet sendes som argument til Set-delen av Property-en som heter
Vekten(), og dette argumentet blir gitt navnet value i vårt tilfelle. Vi kunne kalt det noe
annet (mer om det straks). Det vi typisk ønsker når vi skriver slik, er jo å endre
objektvariabelen vekt, slik at den får verdien 97. Derfor er det fornuftig å ha koden vekt =
value inne i Set-delen.
Merk at vi kunne hatt hvilken som helst kode inne i Get-blokken og Set-blokken. Det er mest
fornuftig å henholdsvis lese og sette (lagre) verdier i tilhørende objektvariabler, men det er
Objektorientering i VB – videregående side 16 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
ikke noe krav om det. En kunne også gjort mye mer, for eksempel loggført det som skjedde til
en tekstfil eller en database, en kunne foretatt feilsjekking (validering) og så videre. Som regel
er det derimot nok å bare lese/sette objektvariablene, men husk for fremtiden at mer går an.
10.4.3. Detaljer og ytterligere forklaring
Det er noen detaljer som er verdt å merke seg, som leder oss til en slags ”beste praksis” ved
bruk av Property i Visual Basic:
Det er vanlig i VB å bruke stor bokstav når en navngir en Property.
Merk at det skal være parentes etter selve navnet på en Property, for eksempel
Vekten().
I klassen Person har vi en objektvariabel som heter vekt. Det er vel og bra, men
siden vi ikke kan ha samme navngiving på to variabler, en funksjon og en variabel, en
variabel og en konstant og så videre, så må vi kalle vår Property for noe annet enn
Vekt().
Vi har valgt Vekten() som navn. Det er litt dumt. Det ville vært bedre å gjøre
motsatt: å la objektvariabelen hete vekten, og så la egenskapen (Property-en) hete
Vekt(). Da ville brukeren kunne skrive lise.Vekt = 62, noe som er mer
naturlig enn å skrive lise.Vekten = 62.
Det er ofte ønskelig å ha logiske navn på sine egenskaper/Properties. En mye brukt
konvensjon for å oppnå dette, er å la objektvariabler starte med prefikset m_, for
eksempel: m_vekt, m_navn, m_hoyde. Bokstaven ”m” står for ”member”, fordi
”objektvariabel” på engelsk gjerne kalles for ”member variable”. Noen bruker o_
som prefiks, og tenker da på ”objektvariabel”. Du velger selv om du i det hele tatt vil
bruke prefiks eller ikke. Gjør du det, så kan du i hvertfall trygt bruke logiske navn på
det du lager som Property-navn, og da blir det enklere å bruke objektet utenfor
klassen.
Det er viktig at selve Property-en er deklarert som Public. Modifikatoren angir
hvor noe skal være synlig, og Public gjør det mulig for Property-en å brukes
utenfor klassen. Det er som regel det vi ønsker.
Vi bruker samme datatype i vår Property som på objektvariabelen som skal behandles.
10.4.4. Hva har en skarve TextBox og en Label å gjøre med en Aha-opplevelse?
Den observante leser har allerede fått et deja vû, men har kanskje ikke lokalisert dette enda.
Vi skal nå gjøre et VIKTIG EKSPERIMENT. Tenk først litt over måten å skrive disse
setningene på:
Dim kari as New Person
Dim ut as String
kari.Vekten = 62
ut = "Kari veier " & kari.Vekten & " kilo"
MsgBox(ut)
Sammenlikn så koden over, med følgende kode:
Dim antallKg as Double
Objektorientering i VB – videregående side 17 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Label1.Text = 62
ut = "Kari veier " & Label1.Text & " kilo"
MsgBox(ut)
Denne koden kunne du ha laget nokså tidlig i din karriere som VB-programmerer. Ser du
likheten? TextBox1.Text, Label1.Text og så videre har samme skrivemåte som vår
bruk av Property. Det er fordi TextBox1 bare er et konkret objekt som er opprettet basert
på klassen TextBox, og denne klassen har tilfeldigvis en Property som heter Text().
Derfor kan vi skrive slik.
Aha! Det er altså sånn det henger sammen! Alle objekter i grensesnittet er nettopp det:
objekter, og da har de selvsagt metoder og Properties (gjerne kalt egenskaper på norsk).
De løse trådene begynner nå å nøste seg sammen i synk med at vi ser nærmere på
mekanismene bak objektorientering. Hvis dette var uklart, så dvel litt ved eksempelet og les
det på nytt på et senere tidspunkt.
Figur 11: Egenskapene (Properties) til en bestemt Label til venstre og en TextBox til høyre. Utviklingsmiljøet lar oss på en enkel måte lese verdiene og endre disse.
Legg merke til hvordan en Label kan ha mange egenskaper som kan endres (se Figur 11) i
utviklingsmiljøet. Egenskapene kontrollerer hvordan objektet oppfører seg. Det fine er at en
også kan endre disse egenskapene i koden. Det er faktisk det som skjer bak kulissene når du
endrer noe i utviklingsmiljøet (ala Figur 11) ! Dette blir kanskje Aha-opplevelse nummer to
for noen. Utviklingsmiljøet er altså bare et grensesnitt inn mot koden, og det er laget for at vi
på en enklere, mer visuell måte, skal kunne fylle objektene våre med innhold!
Dersom du i koden vil gjøre TextBox1 usynlig, er det bare å skrive:
TextBox1.Visible = False
Det som da egentlig skjer, er at Property-en Visible() sin Set-del i klassen som definerer
tekstbokser, utføres. Du kan tilsvarende teste på om en tekstboks er synlig ved å skrive for
eksempel:
If TextBox1.Visible Then
MsgBox("Du kan nå skrive inn noe i tekstboksen, kjære bruker")
Else
MsgBox("Boksen er usynlig, din uheldiggris")
End If
!
Objektorientering i VB – videregående side 18 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Nå er det Get-delen som aktiveres. Den returnerer enten True eller False, avhengig av om
tekstboksen er synlig eller ikke. Hvis den returnerer True, så står det i praksis If True
Then... og da vil meldingsboksen vises med beskjed om at brukeren kan skrive inn noe i
tekstfeltet. Hvis den returnerer False, så står det i praksis If False Then ... og da
blir ikke brukeren like oppmuntret.
10.4.5. En siste Aha-opplevelse
Vi gir oss ikke, nå skal vi helt til bunns i alle hemmeligheter. ”Enter Aha-experience number
three”: Når du lager et program, så starter du gjerne med en Form. Du legger så til en knapp,
du drar litt i hjørnene for å få den større, du endrer kanskje farge og en rekke andre ting. Du
lager så en listeboks, og er fornøyd. Det tar 30 sekunder. Resultatet vises i Figur 12.
Figur 12: En ”form” med en ”button” og en ”listbox” laget på 30 sekunder i utviklingsmiljøet...
Du kunne også programmert alt dette, for hånd. Dersom du i Solution Explorer klikker på det
andre ikonet, så får du se noen ”skjulte” filer. Der finner du blant annet all den koden som
representerer Form1.
Ved å se på koden i filen Form1.Designer.vb, ser vi følgende auto-genererte kode:
Me.Button1 = New System.Windows.Forms.Button
Me.ListBox1 = New System.Windows.Forms.ListBox
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Font = New System.Drawing.Font("Microsoft Sans Serif", 20.0!,
System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, CType(0,
Byte))
Me.Button1.ForeColor = System.Drawing.Color.RoyalBlue
Me.Button1.Location = New System.Drawing.Point(22, 12)
Me.Button1.Name = "Button1"
Me.Button1.Size = New System.Drawing.Size(174, 116)
Me.Button1.TabIndex = 0
Me.Button1.Text = "Min superknapp!"
Me.Button1.UseVisualStyleBackColor = True
'
'ListBox1
'
Me.ListBox1.FormattingEnabled = True
Me.ListBox1.Location = New System.Drawing.Point(230, 33)
Objektorientering i VB – videregående side 19 av 19
Opphavsrett: Forfatter og Stiftelsen TISIP
Me.ListBox1.Name = "ListBox1"
Me.ListBox1.Size = New System.Drawing.Size(120, 95)
Me.ListBox1.TabIndex = 1
'
'Form1
'
Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
Me.ClientSize = New System.Drawing.Size(393, 166)
Me.Controls.Add(Me.ListBox1)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
Dette er altså koden som skal til for å lage grensesnittet i Figur 12! Aha, aha, aha! I koden ser
du noen setninger og uttrykk i fet skrift. Det er for å tydeliggjøre at det som er formattert i
grensesnittet, i bunn og grunn representeres med kode. Listeboksen er dradd noe til høyre på
Form1, og den har en viss størrelse. Dette er kodet vha egenskaper som .Location og .Size. Vi
ser at først opprettes en knapp ved hjelp av koden
Me.Button1 = New System.Windows.Forms.Button
Knappen får en skrifttype, nemlig Microsoft Sans Serif på 20 punkter, og fargen settes til blå:
Me.Button1.Font = New System.Drawing.Font("Microsoft Sans Serif", 20.0! '.......
Me.Button1.ForeColor = System.Drawing.Color.RoyalBlue
Knappen får et navn, og en tekst som vises for brukeren:
Me.Button1.Name = "Button1"
Me.Button1.Text = "Min superknapp!"
Tenk nå over hvor tidkrevende det ville vært å skrive denne koden selv. Du kan selvsagt gjøre
det, hvis du vil, og du kan skrive koden i Notisblokk, hvis du vil, men det tar garantert ikke 30
sekunder. Aha.