Java Programmering - 4. del

Tags:    java
Skrevet af Bruger #4487 @ 29.11.2010

Indledning


Nu hvor vi ved hvad et felt/lokal variabel er, hvordan man laver et nyt objekt og ydermere kan gemme objekter i et fikseret array, kan vi begynde på noget af det mere sjove i programmering. Vi skal f.eks. i denne del lave et lille terningspil, hvor vi kan udskrive resultatet indtil vi har vundet spillet. Men før dette er der lidt mere teori vi skal have styr på. Så lad os gå igang.

Access Modifiers


Indtil nu har vi set på at hver gang vi starter en klasse, skal vi altid skrive ordet public, som det første ord i vores kode. Desuden ved vi at hver gang vi begynder på et felt i vores klasse, skal vi altid bruge ordet private. Disse to ord kaldes for Access Modifiers, på almindeligt dansk kunne vi tænke på det som en slags døre, hvor udefrakommende (typisk andre objekter/klasser) skal have adgang for at få lov til at se indholdet. Selv metoder skal have access modifiers, og lad os nu sige at vores metode var public. Det betyder at alle har adgang til indholdet af den specifikke dør, eller i hvert fald alle objekter af klasser i vores program. Vi kunne ved at lave et objekt af klassen hvor metoden var angivet i, få adgang til denne metode, fra et andet objekt. Det kunne være som vi så i de forrige artikler, hvor vi kunne kalde metoden hentTal(), fra et givent objekt.
Hvis vi nu så havde en metode, som var angivet som værende private, så betyder det at vi ikke har adgang til denne metode udefra klassen. Vi kan med andre ord ikke kalde metoden ved at lave et objekt af denne klasse, også bruge dot notation til at kalde metoden. Når en metode er angivet som private kaldes metoden også for en intern metode, da den jo kun kan bruges inde i det objekt, som den er lavet i. Nu sidder du måske med et spørgsmål som kunne lyde - Hvordan kunne vi få fat i indholdet af f.eks. vores felt heltTal fra før, fra en anden klasse, når feltet nu var angivet med en access modifier der var private? - Svaret på spørgsmålet er at vi heller ikke direkte fik adgang til feltet, men brugte en metode i samme klasse som heltTal feltet, der var angivet som public og som herefter gik ind i feltet og returnerede indholdet af feltet. Du kunne også have lavet feltet public istedet for private, men da vi ved at felter altid skal angives som private, skal vi selvfølgelig ikke gøre dette. Grunden til at de skal være private er fordi, at fejlen for at lave om på data i feltet, som ikke skulle laves om på det tidspunkt, er mindre hvis alt går igennem en intern metode.

Fleksible Arrays (Lister)


Vi lærte jo som sagt om hvordan man lavede fikserede arrays i 3. del, men hvad nu hvis vi ikke ved hvor mange objekter vi vil få af en given klasse, hvordan skulle vi nu angive hvor stor vores indeks skulle være? Svaret er at det kan vi ikke, i hvertfald ikke med at almindeligt array. Men vi kan benytte noget som kaldes et fleksibelt Array. Et fleksibelt array kan have så stort et indeks som vi ønsker, og vi behøver ikke at angive hvor stort indekset skal være fra starten. Men for at bruge sådan et fleksibelt array, skal vi bruge en allerede eksisterende klasse, som andre har skrevet for os. Det er nemlig det smarte ved objektorienteret programmering. Vi kan nemlig genbruge klasser, som allerede er lavet i forvejen, så vi slipper for selv at skulle lave en sådan klasse. Klassen vi skal bruge hedder ArrayList, og den ligger i noget som kaldes Java Biblioteket (Java Libraries). I dette bibliotek ligger alle mulige former for klasser, som man som programmør kan bruge. I dette bibliotek står hvad de forskellige klasser gør, hvilke metoder og konstruktører de har osv. Du kan finde java biblioteket på denne hjemmeside her, og ude i vinduet, hvor der står 'All Classes', kan du så finde klassen ArrayList. Når du klikker på ArrayList klassen, vil du kunne se dokumentationen for denne klasse. Der er nogle ting der er værd at lægge mærke til, f.eks. overskriften, som er - Class ArrayList<E> - selve ordet class er ikke så specielt, da vi ved at dette er en klasse, men det som er specielt er dette ArrayList<E>. Vi kan se at efter navnet ArrayList er der en større end og mindre end tegn, som omkranser bogstavet 'E'. Dette betyder at vi skal specificere et specifikt element når vi vil lave et objekt af et ArrayList. Et element kunne være en primitiv datatype, men det kunne også være objekter af en klasse som vi selv har lavet. Man kan sige at elementet angiver hvilken type af objekter vi kan gemme i vores ArrayList. Da vi ikke kan sige hvilken type af objekter/data, som skal bruges kaldes det også for en Generic Type (på dansk generisk type). Når vi nu ved lidt om dette, er det på tide at lære om hvordan vi laver sådan en ArrayList.

En fleksibel liste af Strings


Lad os her tage et praktisk eksempel på hvordan man implementerer sådan en ArrayList i ens eget eksempel. Lav først en ny klasse, der indeholder en main metode. I denne klasse skal vi så lave en importering af vores klasse ArrayList. En importering betyder bare at vi henter den specificerede klasse, så vi kan lave objekter af den osv. Du laver en importering af klassen ArrayList, ved at bruge statementet import efterfulgt af stien til den klasse du vil importere. Stien for vores ArrayList er java.util.ArrayList. Hele vores import statement ser nu således ud - import java.util.ArrayList; - Statementet skal stå som noget af det første i din kode, også før du laver din klasse, så vores foreløbige kode kunne nu se således ud.
Fold kodeboks ind/udJava kode 

Jeg har kaldt min klasse for 'StringsIArrayList', men du kan kalde din hvad du vil, da dette ikke betyder så meget i dette eksempel. Når vi har importeret klassen ArrayList, er det første vi kan gøre at deklarere en lokal variabel i vores main metode, hvor vi kan gemme vores objekt af klassen ArrayList. Den generiske type, som vores ArrayList skal kunne holde, er Strings, så vores lokale variabel ser nu således ud - ArrayList<String> minArrayList; - navnet på min lokale variabel er minArrayList, og den er nu klar til at indeholde et objekt af klassen ArrayList, med den generiske type Strings. Vi skal nu initialisere vores lokale variabel til at indeholde et objekt af vores ArrayList. Hvis vi kigger på vores ArrayList klasse i java biblioteket, kan vi se længere nede at denne klasse har 3 forskellige konstruktører (constructors). Den første konstruktør kræver ingen paremetre, mens de to andre kræver en eller anden form for parameter. Da vi ikke har tænkt os at ændre på standard opsætningen af denne klasse, tager vi bare den første konstruktør, som laver en almindelig ArrayList for os. Vi skal nu skrive som initialisation til vores lokale variabel - minArrayList = new ArrayList<String>(); - Læg mære til at vi stadig skal fortælle hvilken slags type af data vores ArrayList skal indeholde, selvom det ikke direkte står i konstruktøren. Vores main metode ser nu således ud.
Fold kodeboks ind/udJava kode 

Vi kunne også skrive både deklarationen og initialisationen i en enkelt linje. Dette gøres ofte ved lokale variabler, da det sparer plads i koden. Når man skal sammenføre det, skriver vi bare deklarationen lig med initialisationen. Så vores kode ser nu således ud.
Fold kodeboks ind/udJava kode 

Vi har nu et objekt af klassen ArrayList, og initialiseret det til vores lokale variabel. Vi kan nu kigge på vores klasse ArrayList i java biblioteket endnu en gang. Vi kan gå længere ned i dokumentationen, og her finde de metoder som vi kan bruge når vi har et objekt af klassen ArrayList. Vi kan f.eks. se at der er to metoder der hedder 'add'. Forskellen på disse to metoder, selvom de hedder det samme og tydeligvis gør det samme, er at de skal bruge forskellige parametre. Den første metode skal bruge en parameter, som er et objekt af vores generiske type, som i eksemplet jo var en String. Den anden metode som også hedder add, skal bruge to paremetre. Den første er et int nummer, som angiver hvilken indeks objektet skal indsættes på. Den anden parameter er ligesom før et objekt af vores generiske type, som jo var String i vores eksempel. Da vi ikke har brug for at specificere på hvilket indeks objektet skal indsættes, skal vi bare bruge den metode, som har signaturen add(E e). Vi kan i vores kode via dot notation skrive - minArrayList.add("Her er vores string nummer 1."); - Vi har her så lavet et kald til vores metode add() som ligger i klassen ArrayList. Java ved automatisk at vi vil bruge den første af add metoderne i klassen, fordi vi kun har lavet en parameter da vi brugte metoden.

Mini Opgave Brug add() metoden til at gemme 4 Strings mere i vores ArrayList. Når du har lavet denne lille opgave, så sammenlig din kode med min nedenunder.

Fold kodeboks ind/udJava kode 

Vi kan nu lave en while løkke, som kan udskrive indholdet i vores ArrayList, men før du går i krig med det, skal vi ind i klassen i java biblioteket, og kigge endnu en gang på dens metoder. Vi skal finde en metode, som kan hente/udtrække data fra vores ArrayList, så vi kan udskrive det som vi har gemt. Vi kan når vi kigger f.eks. se at der er en metode der hedder get(int index). Denne metode kan hente indholdet i et specificeret indeks, som bliver specificeret via parameteren. Vi kan altså i parameteren til denne metode specificere hvilket indeks vi vil hente objektet fra. Vi skal også bruge en metode, som hedder Size() og er en simpel accessor metode, som returnerer en int værdi, om hvor mange objekter vi har i vores ArrayList.

Udfordrings Opgave - Lav en while løkke, og brug herefter metoden get() fra vores ArrayList til at hente vores gemte objekter. Som parameter, skal angives hvilket indeks vi vil hente. Brug også metoden Size() til at angive i betingelsen hvornår løkken er slut. Brug også en System.out.println(); statement, til at udskrive indholdet. Når opgaven er klaret, så tjek med min kode nedenfor.

Fold kodeboks ind/udJava kode 

Nu kan du så gemme din kode, kompilere den og køre den. Resultatet skulle gerne se således ud.



Forskellen på en ArrayList og et almindeligt Array, er at hvor et Array er fikseret (altså kun kan indeholde en forudindtaget mængde af objekter), så var vores ArrayList fleksibel (Kunne indeholde en varierende mængde af objekter uden af specificerer det først).

Mutator Metoder


Efter et eksempel med sådan en ArrayList, skal vi have lidt om mutator metoder. Herefter går vi igang med vores første rigtige projekt, nemlig at lave et lille terningspil. En mutator metode var, til forskel fra en accessor metode, en metode som ikke returnerede noget. Mutator metoder bruges som regel til at vise ting, eller lave ændringer i ting. Det kunne f.eks. være at lave en ændring til et felt i et objekt. Hvis du husker tilbage, så brugte en accessor metode en return type, som var den type af data som skal returneres, men da en mutator metode ikke returnerer noget, skal vi bruge nøgleordet void, som betyder at metoden ikke returnerer noget. Et eksempel på en mutator metode kunne se sådan her ud (Metoden adderer et felt der hedder tal, med 10).
Fold kodeboks ind/udJava kode 

Læg mærke til at sådan en metode, til forskel fra en accessor metode, ikke behøver noget return statement til sidst i metoden, da denne jo ikke returnerer noget.

Terningspil


Lad os nu gå igang med vores hoved projekt i denne fjerde del. Vi skal lave et terningspil, hvor formålet med spillet er, at vedblive at slå med terningerne, indtil vi slår 3 seksere i et slag. Der skal kun bruges 5 terninger. Til denne opgave skal vi lave tre klasser, en Terning klasse, en Raflebæger klasse og en Main klasse, hvor vores program køres fra. Lad os gå igang med den første klasse som er Terning klassen.

Terningen
Når vi skal lave vores terning, skal vi tænke på hvad en terning egentlig har til formål. Formålet med terningen er at når vi slår med den skal den vise et vilkårligt tal mellem 1 og 6 (inklusiv). Med denne definition, kan vi udlede at vi i hvert fald skal have et felt til at gemme vores vilkårlige tal i, og vi kan derfor også udlede at vi skal bruge en accessor metode til at returnere indholdet i vores felt.

Udfordrings Opgave - Lav din Terning klasse (Kald klassen for Terning), og gør et felt klar som kan indeholde et helt tal. Gør en konstruktør klar til brug, og lav en simpel accessor metode, som returnerer indholdet i dit nyligt lavede felt. Når du har gennemført denne opgave så tag et kig på hvordan min Terning klasse ser ud.

Fold kodeboks ind/udJava kode 

Vores terning klasse, kan nu returnere indholdet af vores felt, i mit tilfælde har jeg kaldt feltet vaerdi. Vi skal nu have fundet ud af en måde at generere et vilkårligt tal på, som vi så kan gemme i vores felt. Gudskelov er der nogle, som har fundet ud af en måde at generere vilkårlige tal på. De har så gemt det som en klasse, som vi andre kan bruge, og lagt det ind i Java biblioteket. Klassen hedder Random, og ligger i java pakken java.util. Lad os nu importere klassen, og deklarere et felt, så vi er klar til at lægge et objekt af klassen Random ind i dette felt. Vi skal herefter i vores konstruktør initialisere vores nye felt med et objekt af klassen Random.

Udfordrings Opgave - Lav en import statement til Random klassen. lav herefter et felt, som kan indeholde data af typen Random, og initialiser herefter et objekt af Random klassen, til dette felt. Hvis du er i tvivl om hvordan konstruktørerne i Random klassen ser ud, kan du altid slå det op i Java biblioteket. Når du har løst denne opgave, så tag et kig på min kode.
Fold kodeboks ind/udJava kode 

Vi kan nu lave en mutator metode, som har til formål at generere et vilkårligt tal, og herefter gemme dette vilkårlige tal i vores felt vaerdi. Vores Random objekt har en metode, som kan generere et vilkårligt tal. Metoden hedder, hvis du kigger i java biblioteket nextInt, men der er to metoder med dette navn. Vi kunne vælge metoden, som ikke havde nogen parameter, men så ville vi få et vilkårligt tal, som kunne hedde 11456, og vi er kun interesseret i at få vilkårlige tal fra 1 - 6 (inklusiv). Den anden metode som hed nextInt skal bruge 1 parameter, og denne parameter er et tal med typen int. Vi kan ved at læse metodens kommentar, se at metoden nextInt(int n), genererer et nummer imellem 0 (inklusiv), og vores givne tal i parameteren (eksklusiv). Dette betyder at hvis vi giver tallet 6 som parameter, så vil vi kunne få tal mellem 0 (inklusiv), og 6 (eksklusiv). Men vi ville jo gerne have tallene 1 - 6 og ikke 0 - 5. For at løse dette lille problem, kan vi bare addere det vilkårlige tal vi for genereret med 1.

Udfordrings Opgave - Lav en mutator metode, som har til formål at generere et vilkårligt tal imellem 1 og 6 (inklusiv). Husk at metoden skal have en access modifier som er public. Kald metoden noget passende, som f.eks. kastTerning, eller bare kast. Når du har lavet denne opgave, så sammenlign din kode med min.
Fold kodeboks ind/udJava kode 

Nu er vores Terning klasse færdig, og vi kan gå igang med vores Raflebæger klasse.

Raflebæger


Vores Raflebæger klasse har til formål at kunne holde objekter af klassen Terning, og herefter bruge metoderne kast() og hentVaerdi(), til at vise vores vilkårligt genererede tal. Husk at klassen skal hedde Raflebaeger, uden æ, da Java ikke er så glade for æ, ø og å. Vi skal gemme objekterne af klassen Terning i en ArrayList, så lad os starte med at gøre dette klar.

Udfordrings Opgave - Lav en klasse der hedder Raflebaeger, og som indeholder en tom konstruktør. Importer vores ArrayList, og deklarer et felt, som kan indeholde et objekt af ArrayList, med den generiske type Terning. Når du har udført denne opgave, så sammenlig med min.
Fold kodeboks ind/udJava kode 

Vi skal nu initialisere vores ArrayList til at indeholde 5 objekter af klassen Terning. Vi skal bruge metoden add() fra klassen ArrayList, og vi kan bruge en løkke til at kalde denne metode 5 gange, og derfor gemme 5 objekter af klassen Terning, men til dette skal vi lære om en ny form for løkke.

For løkken
Denne nye løkke hedder for, og ligner til forveksling while løkken utroligt meget. Forskellen ligger så i at while løkken initialisere dens værdi inden selve løkkens start ved hjælp af en lokal variabel, hvorefter den laver løkken med dens betingelse. Løkkens forøgelse/tællerskridt sker så inde i løkkens krop. Når man skal benytte en for løkke, så sker disse 3 ting allesammen i for løkkens signatur/header. I teori kunne vi skrive for løkken således, for (Initialisation; Betingelse; Forøgelse). Lad os først se på hvordan while løkken så ud i kode.
Fold kodeboks ind/udJava kode 

Og vores for løkke ser således ud i kode.
Fold kodeboks ind/udJava kode 

Læg mærke til at vores forøgelse ikke hedder i = i + 1;, men i++;, frygt ej. i++;, er bare en anden måde at skrive i = i + 1;. Oparatoren ++ kan kun bruges når du vil addere noget med 1. Ligesom der findes en operator der adderer noget med 1, findes der selvfølgelig også en som subtraherer med 1. Denne oparetor ser således ud --, og man kunne i java f.eks. skrive således i--;, som ville være det samme som at skrive i = i - 1;, men tilbage til vores Raflebaeger klasse. Vi skulle altså lægge objekter ind i vores ArrayList 5 gange ved hjælp af en for løkke. Vi kunne gøre dette i vores konstruktør direkte, men for at lette læsningen af koden i konstruktøren, og selvfølgelig også for at lære noget, skal vi lave initialisationen i en ny mutator metode, som vi kunne kalde initArrayList(). Denne metode skal være en intern metode, så derfor skal access modifieren være private.

Udfordrings Opgave - Vores opgave er altså at lave en intern mutator metode (private), som hedder initArrayList(). Denne metode skal først initialisere vores felt, til at indeholde et objekt af ArrayList. Herefter skal den indeholde en for løkke, som bruger vores metode add() fra vores objekt af ArrayList, til at lægge et nyt objekt ind af klassen Terning. Det skal den gøre 5 gange, da vi skal have 5 forskellige objekter af klassen Terning. Når metoden er færdig, så lav et internt kald i din konstruktør til denne metode, ved at skrive initArrayList();. Når du har lavet denne opgave, så sammenlign koden med min.
Fold kodeboks ind/udJava kode 

Nu har vi så en ArrayList som gemmer 5 terninger. Vi kan nu lave en metode, som har til formål at bruge metoden kast(), for hver af vores 5 terninger, for at generere et vilkårligt tal, og herefter hente tallet fra vores vaerdi, via metoden hentVaerdi(). Metoden skal så udskrive værdierne, og herefter lave et tjek, for at finde ud af om vi har fået 3 seksere. Hvis vi har 3 seksere, skal den sætte et nyt felt, som vi kunne kalde gameOver, til true. Dette var meget på en gang, men lad os prøve at tage opgaven i små trin.

1. Deklarer et nyt felt i klassen, som hedder gameOver. Feltet skal kunne indeholde data af typen boolean.
2. Initialiser feltet gameOver i din konstruktør, til at indeholde værdien false.
3. Lav nu en ny mutator metode, som har en public access modifier. Denne metode kunne f.eks. hedder kastTerninger().
4. Benyt enten en for løkke eller en while løkke. Løkken skal gå igennem hvert af vores objekt i vores ArrayList, så husk at du kan bruge metoden fra klassen ArrayList, som hedder size(), i løkkens betingelse. I løkkens krop skal du bruge dot notation til at kalde Terning klassens kast() metode. benyt dig af ArrayListens metode get() til at hente hvert af vores forskellige objekter.
5. Brug herefter så vores hentVaerdi() metode, med hvert objekt, i vores løkke, men lav dog først en lokal variabel før vores løkke, som har datatypen String og navnet str. Du kan samtidig initialisere denne lokale variabel, men denne gang lav både deklarationen og initialisationen i en linje. Det kunne f.eks. se sådan her ud - String str = ""; - Vi skal herefter tilføje denne variabel med resultatet fra vores hentVaerdi(). I løkken skriver du så str += ""+terninger.get(i).hentVaerdi()+" ";.
6. Herefter laver du en lokal variabel, og initialiserer den i samme linje med værdien 0 (nul), som du kalder antalSeksere med datatypen byte. Husk at placere variablen uden for løkken.
7. lav nu inde i den løkke en if statement, som tjekker om vores hentVaerdi() returnerer værdien 6, med operatoren ==. Hvis den gør, skal den køre koden i if statementet. I koden i if statementet skal vi addere variablen antalSeksere med 1.
8. Nu er vores løkke færdig. Efter løkken skal du nu lave en println(); statement, som udskriver vores lokale variabel str. Vi kunne også tilføje feltet antalSeksere, for at udskrive antallet af seksere, i samme linje.
9. Lav et if statement, som tjekker om indholdet i antalSeksere er større end eller lig med 3. Hvis den er det, så initialiser indholdet af feltet gameOver til at være true.

Koden ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu er vores metode kastTerninger() færdig. og vores klasse Raflebaeger er også snart færdig. Vi mangler bare en enkelt accessor metode, som returnerer værdien af feltet gameOver. Husk at gameOver er en data af typen boolean. Nu ser vores kode sådan her ud med denne accessor metode i.
Fold kodeboks ind/udJava kode 

Nu er vores Raflebaeger klasse færdig, og vi skal nu til vores Main klasse.

Main klassen


Vores main klasse skal indeholde en main metode. Denne main metode skal have en lokal variabel, som kan indeholde et objekt af klassen raflebaeger. Herefter skal du lave en while løkke, som har en betingelse, som tjekker om vores metode hentGameOver() er lig med værdien false. Hvis den er det, så skal løkken køres. Bemærk at denne while løkke ikke behøver en initialisation, eller en forøgelse, da vi benytter en boolean værdi. Løkken stopper først når feltet gameOver returnerer true, og det gør den jo først når vores metode kastTerninger() har 3 eller flere seksere. I løkkens krop skal du køre metoden kastTerninger fra Raflebaeger klassen, via dot notation. Vores kode ser nu sådan her ud.
Fold kodeboks ind/udJava kode 

Vi mangler en sidste ting til vores main metode. Under løkken laver du to println(); statements. Den første skal være uden indhold i parameteren, og den anden skal have en konstant String, som udskriver teksten "Du har vundet spillet!". Vores Fulde Main klasse, ser nu således ud.
Fold kodeboks ind/udJava kode 

Nu er spillet færdigt, og du kan nu kompilerer dine java filer, og herefter udføre din Main fil. Outputtet i din kommandoprompt ser nu måske sådan her ud.



Nu er vi færdige med fjerde del i denne Java kavalkade. Følg med i femte del, hvor du skal lære meget mere om hvordan man programmerer i Java.

Hvad synes du om denne artikel? Giv din mening til kende ved at stemme via pilene til venstre og/eller lægge en kommentar herunder.

Del også gerne artiklen med dine Facebook venner:  

Kommentarer (2)

User
Bruger #17601 @ 09.06.13 18:18
Jeg synes det et en rigtig god måde at lære at programmere på. læse lidt, lave en øvelse, og så tjekke om man har lavet den rigtigt, så tak for det Martin.
Jeg synes måske progressionen her i kapitel 4 går lidt for hurtigt frem.
2 spørgsmål.
i Raflebaegerklassen er der en for løkke hvor man skriver
for (int i =0;i<5;i++){
terninger.add(new Terning();
}
- jeg kan ikke se at man bruger "int i" til noget i denne løkke, og det undrer mig at man kan skrive (new Terning) parentesen, da der tidligere stod at der kun var et parameter i add-metoden, og det var "objekt af typen"??

I Terning-klassen er der både en "kast", og en "hentVaerdi" - metode. Er det nødvendigt? kan man ikke bare nøjes med en metode som genererer et random ml. 1 - 6 og returnerer værdien?
m.v.h. Martin
User
Bruger #4487 @ 09.06.13 23:18
Hej Martin

int i bliver brugt i løkken til at inkrementerer løkken. I løkkens hoved er for(int i = 0; i < 5; i++), som er det smarte ved for løkken fordi vi kan have både initialisationen, betingelsen og inkrementeringen samme sted.

new Terning() betyder at man opretter et nyt objekt af klassen Terning. Vores add() metode får derfor et Terning objekt som parameter på denne måde. Alternativt kunne man gøre således
Fold kodeboks ind/udJava kode 


og til sidst. Jo, du kunne sagtens lade metoden 'kast()' returnerer terningens værdi fra kastet, det er noget du selv bestemmer. Det smarte med en hentVaerdi() metode er at vi senere kan hente værdien fra et kast, hvis ikke der har været kastet en gang før, men det er som man vælger at tage det.
Du skal være logget ind for at skrive en kommentar.
t