INF1010 MVC i tekstbaserte programmer Marit Nybakken marnybak@ifi.uio.no 9. februar 2004 Marit har ingen utdanning innen systemutvikling og vet antageligvis ikke hva hun prater om. Hun har dog skumlest noen artikler under sterk påvirkning av koffein. MVC-designet var opprinnelig laget for programmer med grafisk brukergrensesnitt, og det er nok ikke rett frem hvordan man overfører dette til tekstbaserte programmer. Derfor vil dere høre litt forskjellige løsninger avhengig av hvilken gruppelærer dere spør. Model - View - Control Vi skal altså forsøke å dele opp programmene våre i tre deler: View : styrer grafisk eller tekstlig utskrift til skjerm om statusen til modellen. Viser altså rett og slett frem hvordan modellen ser ut akkurat nå. Control : tar i mot input fra mus og keyboard fra brukeren om ønskede endringer av systemet. Ber modellen endre på seg ut i fra dette. Model : holder datamodellen, styrer oppførselen til dataene. Tar i mot forespørsler om informasjon om status (fra view) og forespørsler om å endre status (fra kontroll). Skal også gi view beskjed når den har endret seg slik at view kan oppdatere. 1
Et GUI-eksempel Vi skal først se hvordan dette vil fungere i et program med grafisk brukergrensesnitt. Vi tenker oss et eksempel der vi har en grafisk modell av en liten harepus. Vi har et vindu som viser frem harepusen på skjerm. Det skal være mulig å legge til punkter på harepusen ved hjelp av musen. View er nå vinduet som viser frem harepusen på skjerm. Model er den grafiske modellen, representasjonen av harepusen, kanskje en rekke punkter som det skal trekkes linjer mellom. Control er den delen som lytter på musen og ber modellen legge til punkter ut i fra hvor brukeren klikker. Se figur 1. Hvordan foregår kommunikasjonen her? Kontroll har en peker til modellen. Hver gang den får inn et museklikk, oversetter den dette til koordinater og kaller en metode modell.leggtilpunkt(x,y); i modellen, den oppdaterer modellen. View må kunne vite når harepusen har fått flere punkter for å kunne oppdatere skjermbildet med den nye harepusen. Modellen har derfor en peker til View og sier i fra via et metodekall (eventuelt et slags signal) view.endringskjedd() når leggtilpunkt-metoden blir kalt. View kan deretter få de oppdaterte dataene gjennom en parameter til endringskjedd() (et slags oppdateringsobjekt med nødvendig informasjon) eller den kan ved behov kalle en metode i modellen, Data d = modell.fådata() for å hente ut de dataene den selv mener den har behov for. I det siste tilfellet må View ha en peker til modellen. Hva er egentlig problemet? Når vi har et grafisk brukergrensesnitt er det enklere å forestille seg hvordan ting bør fungere. For view har vi et eller flere vinduer som på en eller annen 2
Figur 1: Kommunikasjon mellom view, control og model 3
Figur 2: Kommunikasjon mellom view, control og model, tekstbasert? 4
fin måte til enhver tid viser frem hvordan modellen ser ut. Modellen sender ut signaler når den endrer seg. I mange språk trenger ikke modellen engang vite hvem som skal fange opp disse signalene. View registrerer seg for å motta signaler fra modellen, og oppdaterer seg når den mottar et signal. I et tekstbasert program med en meny blir modellen kun vist frem når vi ber om det gjennom et menyvalg. Dette gjør at koden blir helt annerledes. Tekstbasert løsning Vi har i oblig 1 en situasjon der noen av menyvalgene dreier seg om å vise frem deler av modellen (vis person, vis søsken, fetter/kusine, flest barn), og noen dreier seg om å endre modellen (ny person, ny far/mor, ekteskap, skilsmisse). De som dreier seg om å endre modellen er ren kommunikasjon mellom kontroll og modell (kontroll: endre på deg! modell: jepp, ferdig, gikk bra!). Dette fungerer omtrent som det ville gjort for et grafisk grensesnitt. Kontrolldelen i et grafisk grensesnitt kan heldigvis også bestå av et eget kontrollvindu med knapper, tekstfelt, slidere og statusmeldinger. Dette gir grunnlag for å la kontroll skrive ut ting på skjermen, den også. De som dreier seg om å vise frem modellen er noe man kanskje kunne tenkt seg ville være på skjermen hele tiden når man har grafisk brukergrensesnitt. Input kreves for noen av fremvisningene, f.eks. navn til person som skal vises frem, og dette kan gis via tekstfelt og knapper. Disse tekstfeltene vil i såfall være en del av views kontroll, ikke modellens kontroll, som bare dreier seg om å endre på modellen (jepp, vi kan ha flere kontroller). Vi skulle gjerne ha beholdt vårt gode gamle system med en ordreløkke som tar seg av alle menyvalg, selv om de nå i og for seg tilhører to forskjellige kontrollsystemer. Men vi kan slå sammen viewkontroll og modellkontroll til en kontroll, og da kan hele menyen befinne seg på samme sted. Menyvalg som har med endring av modell å gjøre resulterer i kall på metoder i modellen. Menyvalg som har med fremvisning å gjøre resulterer i kall på metoder i view. View må deretter kalle passende metoder i modellen for å hente ut informasjonen den skal vise frem. Eventuelle input til hva som skal vises frem, f.eks. navnet til personen, skal leses inn i Kontroll (dette tilsvarer tekstfeltet og knappene som kontrollerer view). 5
I det hele tatt... Se på figur 2 du. Eksempel på kode class Kontroll { View view; Register reg; void ordrelokke() { // Skriv ut meny // Les inn valg switch(valg) { 10 case 1: leggtilperson(); break; case 2: visperson(); break; // osv... void leggtilperson() { // Les inn navn, mor, far, kjønn System.out.print("Navn: "); String navn = tast.intext(); // Osv... // Be register om å oppdatere modellen boolean ok = reg.leggtilperson(navn, mor, far, kjønn); 20 if(ok) { 30 System.out.println("Gikk fint ja"); else { System.out.println("Dette gikk åt skogen"); void visperson() { System.out.print("Navn: "); String navn = tast.intext(); 40 // Be view om å vise frem modellen 6
view.visperson(navn); class Register { // Modell HashMap personer = new HashMap(); 50 boolean leggtilperson(string navn, String mor, String far, char kjønn) { //... if(!personer.containskey(navn)) { // Legge til fyren/dama //.... return true; else{ return false; 60 String visperson(string navn) { // Finne person og lage infotekst om ham // Et alternativ her kunne vært å bare returnere peker til personen return info; 70 class View { Register reg; void visperson(string navn) { String res = reg.visperson(navn); System.out.println(res); void vissøsken(string navn) { String res = reg.vissøsken(navn); System.out.println(res); 80 // osv... 7
Kontroll får altså lov til å skrive på skjerm når den ber om input fra tastaturet og skrive ut resultatet av oppdateringer av modellen (som stort sett blir feilmeldinger eller det-gikk-fint-meldinger). Når modellen skal vises frem, er det View som tar seg av utskriften på skjerm. 8