Les dette før du begynner på oppgaven.
- Hold deg til de identifikator-navnene
som er brukt i oppgaveteksten, dog med unntak av metodenes parameternavn som kan
velges fritt.
- Dersom det er en deloppgave du ikke får til, bør du gå videre til den neste.
Får du bruk for en metode fra en deloppgave du ikke har gjort, kan du
gjøre kall på metoden selv om du ikke har programmert den. Du forutsetter da at
den utfører det den er tiltenkt å gjøre. Det er viktig at du svarer (i alle
fall litt) på alle deloppgavene.
- Merk deg at svært mye av programmeringen går ut på å gjøre kall på passende
metoder av dem som er omtalt i oppgaven. Merk deg derfor hva de omtalte metodene
utfører. Pass på ved metodekall at argumenter er av riktig type og sørg for å
gjøre bruk av dataene som metodene returnerer.
- Svar nøyaktig på det du blir spurt om.
Dersom du mener at oppgaveteksten ikke gir deg tilstrekkelig informasjon
eller er uklar, kan du gjøre dine egne forutsetninger. Gjør i så fall rede for
disse.
- Ved sensur vil alle delpunktene telle likt.
KØSYSTEM PÅ PASSKONTOR
I denne eksamensoppgaven skal du lage et java-program som håndterer køen av kunder på et
passkontor i en større by, tilsvarende det vi har på politihuset i Oslo.
Passkontoret har stor pågang av kunder som trenger nytt pass, og i travle
perioder kan ventetiden bli lang. En av utfordringene for de ansatte er å håndtere køen av
kunder på en god måte.
Når man kommer inn på passkontoret møter man en kølappautomat med to knapper. Skal man søke om pass,
trykker man på knappen for det, skal man hente pass trykker man på den andre knappen.
Godt synlig i lokalet står det en opplysningstavle som viser hvilket kølappnummer som står
for tur til å bli ekspedert, hvilken type kølapp det gjelder og hvilken luke kunden med kølappen skal gå til.
Bildene under viser
brukergrensesnittene til klassene som simulerer henholdsvis kølappautomaten (til venstre)
og opplysningstavlen (til høyre).
Ekspederingen av passkundene er fordelt på 15 luker. Lukene er av to typer.
12 av dem er reservert for kunder som skal søke om pass, mens i de resterende 3 blir det
kun levert ut ferdige pass. På neste side ser du to bilder av brukergrensesnittet til klassen som simulerer lukene.
På rammen står det enten"Søke pass" eller "Hente pass", alt etter hva slags luke det dreier seg om.
Øverst på displayet står det lukens nummer, og deretter står det nummer på kølappen som skal ekspederes.
Når saksbehandleren er ferdig med en kunde og klar for neste, trykker vedkommende på "Ekspeder neste"-knappen.
Programmet består av den abstrakte superklassen Kølapp
, subklassene SøkeKølapp
og
HenteKølapp
, klassen Kø
som inneholder en array med kølapper,
klassen KøSystem
som inneholder to køer (søke-kø og hente-kø),
klassen KølappAutomat
som simulerer kølappautomaten, klassen Luke
som
simulerer en luke der kunder blir ekspedert, klassen LukeArray
som inneholder en array av luker, klassen OpplysningsTavle
som simulerer opplysningstavlen og til slutt driverklassen
Passkontor
som inneholder main-metoden.
Som du ser er det mange klasser, men til gjengjeld er det svært få metoder i hver klasse.
De enkelte oppgavene inneholder nærmere informasjon.
OPPGAVE 1
Den abstrakte superklassen Kølapp
har to konkrete subklasser SøkeKølapp
og
HenteKølapp
. I denne oppgaven skal du programmere klassene Kølapp
og SøkeKølapp
.
(Klassekroppene i de to subklassene vil bli identiske, og derfor holder det å programmere den ene her.
Det er likevel nødvendig å ha begge subklassene med i det endelige programmet. )
Superklassen Kølapp
skal kun ha følgende datafelt og metoder:
- Et datafelt som representerer kølappens nummer.
- En konstruktør som initialiserer kølappens nummer. Kølappens nummer skal være parameter.
- En get-metode som returnerer kølappens nummer.
a) Programmer klassen Kølapp
.
Subklassen SøkeKølapp
skal kun ha følgende datafelt og konstruktør:
- Et static datafelt som skal brukes til å generere et nytt, ubrukt kølappnummer.
- En parameterløs konstruktør som initialiserer kølappens nummer.
b) Programmer klassen SøkeKølapp
.
OPPGAVE 2
I denne oppgaven skal du programmere metoder i klassen Kø
.
Du kan forutsette at kølappene befinner seg kontinuerlig etter hverandre i arrayen.
Nedenfor ser du en skisse av klassen.
public class Kø
{
private Kølapp[] kø;
private int antall = 0; // antall kølapper som er satt inn i arrayen
private int neste = 0; // indeks for kølapp som står for tur til å
// bli ekspedert
< Konstruktør som skal opprette arrayen kø.
Lengden på arrayen skal mottas som parameter. >
public boolean tomKø()
{
< Hvis køen er tom, skal metoden returnere true,
i motsatt fall skal den returnere false. >
}
public boolean settIKø( Kølapp k )
{
< Metoden skal sette parameteren k inn i arrayen, under
forutsetning av at det er plass. Hvis så er tilfelle,
skal metoden returnere true, i motsatt fall skal den
returnere false. (NB! Når en person trekker en kølapp,
vil denne metoden bli kalt opp.) >
}
public int ekspeder()
{
< Metoden skal returnere nummeret tilhørende kølappen
som står for tur til å bli ekspedert, under forutsetning
av at det står noen i kø. Hvis køen er tom, skal metoden
returnere -1. >
}
} // end of class Kø
a) Programmer
- klassens konstruktør.
- metoden
tomKø().
b) Programmer metoden settIKø(Kølapp k)
.
c) Programmer metoden ekspeder()
.
OPPGAVE 3
I denne oppgaven skal du programmere metoder i klassen KøSystem
.
Foruten konstantene SØKE_PASS
og HENTE_PASS
har klassen to Kø
-objekter: et som skal håndtere køen av personer som skal
søke om pass, og et annet som skal håndtere køen av personer som skal hente pass.
Nedenfor ser du en skisse av klassen.
public class KøSystem
{
public static final int SØKE_PASS = 1, HENTE_PASS = 2;
Kø søkeKø, henteKø;
< Konstruktør som skal opprette objektene søkeKø og henteKø.
Lengden på arrayene i Kø-objektene skal mottas som parametre.
Disse kan være av forskjellig lengde. >
public boolean tomKø( int type )
{
< Hvis køen, av den typen som parameteren type angir, er tom,
skal metoden returnere true. I motsatt fall skal metoden
returnere false. >
}
public int trekkKølapp( int type )
{
< Metoden skal opprette et kølapp-objekt, av den typen som
parameteren type angir, og så sette det inn i riktig kø, under
forutsetning av at dette lar seg gjøre. Metoden skal deretter
returnere kølappens nummer. Hvis det ikke lar seg gjøre å sette
inn kølappen, skal metoden returnere -1. >
}
public int ekspeder( int type )
{
< Metoden skal returnere nummeret til kølappen som står
for tur til å bli ekspedert i den type kø som parameteren
type angir. Hvis denne køen er tom, skal metoden returnere -1. >
}
}// end of class KøSystem
a) Programmer
- klassens konstruktør.
- metoden
tomKø().
b) Programmer metoden trekkKølapp( int type )
.
c) Programmer metoden ekspeder( int type )
.
OPPGAVE 4
Over ser du et bilde av brukergrensesnittet til klassen KølappAutomat
,
og under finner du en skisse av klassen.
< import-setninger >
public class KølappAutomat extends JFrame
{
private JButton søkePass, hentePass;
private JTextField kønr;
private KøSystem ks;
public KølappAutomat( KøSystem k, String s )
{
super( s ); // Rammeteksten
ks = k;
< Setter opp brukergrensesnittet. >
Knappelytter lytter = new Knappelytter();
søkePass.addActionListener( lytter );
hentePass.addActionListener( lytter );
}
public void melding( JTextField tf, Color c, int str, String tekst )
{
tf.setFont(new Font("Times", Font.BOLD, str));
tf.setBackground( c );
tf.setText(tekst);
}
< Privat lytteklasse som fanger opp klikkene på knappene
"SØKE PASS" og "HENTE PASS". Lytteklassen skal sørge for at
kølapp-objekt av riktig type settes inn i køsystemet. Klikkene
tilsvarer det å trekke en kølapp, og kølappens nummer skal
vises i tekstfeltet. >
} // end of class KølappAutomat
a) Programmer den private lytteklassen Knappelytter
.
OPPGAVE 5
Over ser du et bilde av brukergrensesnittet til klassen OpplysningsTavle
,
og under finner du en skisse av klassen.
< import-setninger >
public class OpplysningsTavle extends JFrame
{
private JTextField typefelt, nrfelt, lukefelt;
private KøSystem ks;
public OpplysningsTavle( KøSystem k, String s )
{
super( s );
ks = k;
< Setter opp brukergrensesnittet. >
}
public void melding( JTextField tf, Color c, int str, String tekst )
{
< Som beskrevet i klassen KølappAutomat. >
}
public int ekspederNeste( int lukeNr, int luketype )
{
< Metoden blir kalt når det i en luke klikkes på "Ekspeder neste"-knappen
(se oppgave 6). Metoden mottar lukens nummer og type som parametre, og
skal sørge for at neste kunde med kølapp av riktig type blir ekspedert,
under forutsetning av at det står noen i denne køen.
Hvis dette er tilfelle skal opplysningstavlen oppdateres:
- I det øveste tekstfeltet skal det skrives "Søke pass" eller "Hente pass",
avhengig av parameteren luketype.
- I det midterste tekstfeltet skal det skrives "Kølapp" etterfulgt av
kølappens nummer.
- I det nederste skal det skrives "Gå til luke" etterfulgt av lukens
nummer.
Til slutt skal metoden returnere kølappens nummer. Hvis køen
(av den aktuelle typen) er tom, skal metoden returnere -1. >
}
} // end of class OpplysningsTavle
a) Programmer metoden ekspederNeste( int lukeNr, int luketype )
.
OPPGAVE 6
Over ser du to bilder av brukergrensesnittet til klassen Luke
.
For hver luke skal lukens type, lukens nummer og navnet
på saksbehandleren lagres. I tillegg er det et datafelt, antallKunder
, som skal holde rede på
hvor mange kunder saksbehandleren til enhver tid har ekspedert. Under finner du en skisse av klassen:
< import-setninger >
public class Luke extends JFrame
{
private int lukeType;
private int lukeNr;
private String saksbehandler;
private int antallKunder;
private JButton ekspeder;
private JTextField lukefelt, nrfelt;
private OpplysningsTavle tavle;
public Luke(String navn, int type, int nr, OpplysningsTavle ot )
{
super( ( type == KøSystem.SØKE_PASS ) ? "Søke pass" : "Hente pass" );
saksbehandler = navn;
lukeType = type;
lukeNr = nr;
tavle = ot;
antallKunder = 0;
Knappelytter lytter = new Knappelytter();
ekspeder.addActionListener( lytter );
< Setter opp brukergrensesnittet. >
}
public void melding(JTextField tf, Color c, int str, String tekst)
{
< Som beskrevet i klassen KølappAutomat. >
}
< get-metoder for saksbehandler og antallKunder >
< toString()-metode som skal returnere verdiene til datafeltene
lukeNr, saksbehandler og antallKunder i form av en tekst. >
public void ekspederNesteKunde()
{
< Metoden bli kalt når saksbehandleren i luka klikker på
"Ekspeder neste"- knappen. Metoden skal sørge for at opplysningstavlen
i lokalet blir oppdatert, slik det er beskrevet i "ekspederNeste"-metoden
i oppgave 5. I tillegg skal lukens eget tekstfelt "lukefelt" oppdateres
med kølappnummeret til neste kunde som skal ekspederes. Hvis det ikke
står noen i kø, skal dette tekstfeltet blankes ut. >
}
< Privat lytteklasse som kaller ekspederNesteKunde()
når det klikkes på "Ekspeder neste"- knappen. >
} // end of class Luke
a) Programmer
- get-metoder for
saksbehandler
og antallKunder.
toString()
-metoden.
b) Programmer metoden ekspederNesteKunde()
.
OPPGAVE 7
Som nevnt i oppgavens innledning, er det til tider stor pågang av kunder som ønsker nytt pass.
Av denne grunn ønsker arbeidsgiveren å få informasjon om hvor mange passøknader som er
behandlet i løpet av en dag,
gjennomsnittlig antall passøknader pr luke, hvilken saksbehandler som har behandlet flest søknader,
og rangering av saksbehandlerne (lukene) ut fra hvor mange søknader hver har behandlet i løpet av arbeidsdagen.
Metoden skrivStatistikk()
presenterer den
ønskede informasjonen i et dialogvindu og blir kalt opp fra når programmet avsluttes:
(se windowClosing
-metoden i hovedprogrammet til slutt i oppgaven.)
Nedenfor ser du en skisse av klassen LukeArray
.
< import-setninger >
public class LukeArray
{
private Luke[] lukene;
public LukeArray(OpplysningsTavle tavle, int type, int startnr, String[] navn)
{
< Konstruktøren skal opprette Luke-arrayen. Denne skal være like lang
som lengden på String-arrayen som mottas som parameter. Deretter skal
lukearrayen fylles med Luke-objekter. Lukene skal nummereres etter økende
nummer, der parameteren "startnr" angir nummeret til det første
Luke-objektet som settes inn i arrayen. >
}
public int totaltAntallKunder()
{
< Metoden skal returnere det totale antall kunder som er blitt eksedert
i lukene tilsvarende Luke-objektene i arrayen. >
}
public double snittAntallKunderPrLuke()
{
< Metoden skal beregne og returnere gjennomsnittlig antall kunder som
er blitt ekspedert i lukene tilsvarende Luke-objektene i arrayen. >
}
public Luke flestKunder()
{
< Metoden skal returnere det Luke-objektet som tilsvarer luken der det
er behandlet flest kunder. >
}
public String dagensSaksbehandler()
{
< Saksbehandleren som har ekpedert flest kunder blir kåret til
"Dagens saksbehandler". Metoden skal returnere navnet til vedkommende. >
}
public void sortertArray()
{
< Metoden skal sortere Luke-objektene i arrayen etter antall ekspederte
kunder, slik at det Luke-objektet som tilsvarer luken der det er
behandlet flest kunder står først. (Sorteres etter minkende antall.) >
}
public String toString()
{
< Metoden skal returnere all informasjon som er lagret i Luke-objektene
i arrayen. Informasjonen skal skrives ut i sortert rekkefølge
etter sorteringskriteriene som er beskrevet i sortertArray()-metoden. >
}
public void skrivStatistikk()
{
< Viser dialogvinduet som det er bilde av på forrige side.
Denne metoden skal du IKKE programmere. >
}
} // end of class LukeArray
a) Programmer klassens konstruktør.
b) Programmer metodene
totaltAntallKunder().
snittAntallKunderPrLuke().
c) Programmer metodene
flestKunder().
dagensSaksbehandler().
d) Programmer metoden sortertArray()
.
e) Programmer metoden toString()
.
SLUTT PÅ OPPGAVENE
Til orientering er klassen Passkontor
, som
inneholder main-metoden, lagt ved:
< import-setninger >
public class Passkontor
{
public static void main( String[] args )
{
KøSystem køene = new KøSystem(100, 50);
OpplysningsTavle tavle = new OpplysningsTavle(køene, "");
String[] saksbehandlere1 =
{"Olsen", "Hansen", "Berg","Johansen", "Lie", "Andersen", "Kielland", "Moe"};
final LukeArray søkelukene =
new LukeArray(tavle, KøSystem.SØKE_PASS, 1, saksbehandlere1);
String[] saksbehandlere2 = { "Jensen", "Furuholmen", "Harket"};
final LukeArray hentelukene =
new LukeArray(tavle, KøSystem.HENTE_PASS,
saksbehandlere1.length + 1,saksbehandlere2);
KølappAutomat automat = new KølappAutomat(køene, "Kølappautomat");
tavle.addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent e )
{
søkelukene.skrivStatistikk();
System.exit( 0 );
}
} );
} // end of main
}// end of class Passkontor