Les gjennom hele oppgavesettet før du begynner å besvare deloppgavene.
Som student bruker du sikkert kollektive transportmidler i Oslo og er kjent med Ruters billettsystem for kollektivtrafikken. Ruter har, etter mange år, omsider fått sitt nye billettsystem til å virke. Du får nå i oppgave å lage et tilsvarende billettsystem, som vi her kan kalle Ruter#PLUSS. Systemet skal lages i java og ha tilsvarende funksjonalitet. For at oppgaven ikke skal bli alt for stor (du har jo bare 5 timer, mens Ruter brukte mange år!) skal vi holde oss til Ruters sone 1, dvs. lage et system som gjelder for reiser innenfor Oslos grenser. Videre skal vi begrense oss til tre typer reisekort (billetter) som vi gir nye navn: Det som Ruter kaller for smartbillett heter her Klippekort, det som Ruter kaller for 24-timersbillett heter her Dagskort og det som Ruter kaller for 30-dagersbillett heter her Månedskort. Ruter#PLUSS skal imidlertid bygges opp på en slik måte at det lett vil kunne utvides med både flere billettyper og soner.
Programmet består av et klassehierarki med superklassenReisekort
, og subklassene
Klippekort
, Dagskort
og Månedskort
.
Klassen ReisekortSystem
utgjør, sammen med klassehierarkiet, programmets datastruktur.
Programmet skal ha tre vinduer, et for salg av reisekort, et som simulerer billettkontrollen der kortene valideres,
og et vindu beregnet på administrasjonen. De tre vindusklassene er Reisekortsalg
, Kontrollvindu
og Administrasjonsvindu.
Klassen RuterPluss
er programmets driverklasse og inneholder main-metoden.
Den administrative delen i programmet skal lagre opplysninger om hvor
mange kort som er solgt av de forskjellige korttypene, hvor mye det er solgt for (i antall kroner)
av de forskjellige korttypene, og hvor mye det er solgt reisekort for totalt.Klippekort
, et Dagskort
eller et Månedskort
.
Du skal i denne deloppgaven fullføre definisjonen av den abstrakte superklassen ReiseKort
,
klassen som skal være superklassen for de forskjellige korttypene.
Nedenfor ser du en skisse av klassen:
import java.util.Calendar; import java.text.DateFormat; public abstract class Reisekort { private Calendar utløpstidspunkt; // Blir tildelt verdi når kortet valideres < kortNr - et unikt nummer som identifiserer hvert enkelt reisekort > < pris - hva kortet koster i hele kroner > < hjelpevariabel for å generere et unikt kortNr > < konstruktør som mottar prisen som parameter og som tildeler reisekortet et unikt kortNr > < set-metode for utløpstidspunkt > < get-metoder for kortNr, pris og utløpstidspunkt > public String gyldigTil() { if ( utløpstidspunkt == null ) return null; DateFormat tf = DateFormat.getDateTimeInstance ( DateFormat.LONG, DateFormat.MEDIUM ); return tf.format(utløpstidspunkt.getTime()); } public boolean gyldig() // Metoden vil bli redefinert av subklassene { Calendar nå = Calendar.getInstance(); return nå.before( utløpstidspunkt ); } } // end of class Reisekorta) Fullfør definisjonen av
Reisekort
ved å erstatte all pseudo-kode med java-instruksjoner.
De neste to deloppgavene går ut på å programmere metoder i klassen
Klippekort
. Et Klippekort
er et verdikort der man setter inn penger.
Hver gang man foretar en reise, skal kortet valideres i billettkontrollen. Hvis det er nok
penger på klippekortet, er kortet gyldig som billett i en time.
Et reisekort kan "lades opp" ved at man setter inn penger på kortet.
I den neste oppgaven vil du få bruk for å kunne lagre et tidspunkt.
Til dette kan du bruke et Calendar
-objekt som du oppretter ved å skrive:
Calendar dato = Calendar.getInstance();Hvis du ønsker å øke tidspunktet
dato
med en time, skriver du:
dato.add( Calendar.HOUR_OF_DAY, 1 );
Nedenfor ser du en skisse av denne klassen:
import java.util.Calendar; public class Klippekort extends Reisekort { public static final int PRIS_PER_REISE = 28; private int saldo; // beløpet som til enhver tid er igjen på klippekortet private static int antallSolgte = 0; // Det totale antall solgte klippekort private static int sumAlleKlippekort = 0; // Den totale summen som er satt inn // på alle klippekortene til sammen. < Konstruktør som mottar det beløpet som skal settes inn på kortet ved opprettelsen av det. Foruten å sørge for å initialisere klassens datafelt, skal den også sørge for å oppdatere antall solgte klippekort og ikke minst summen det er solgt klippekort for så langt. > < get-metoder for saldo, sumAlleKlippekort og antallSolgte > public boolean gyldig() // Blir redefinert her! { < Metoden kalles hver gang man skal foreta en reise med klippekortet. Kortet er gyldig hvis det brukes innen utløpstidspunktet. (Det er gyldig i en time etter at man har betalt.) Hvis kortet brukes etter utløpstidspunktet, skal metoden sjekke om det er nok penger på kortet til å foreta reisen. I så fall er kortet også gyldig og nytt utløpstidspunkt må settes i tillegg til at saldoen reduserer. Returverdien skal angi utfallet av valideringen. > } public void ladOpp( int beløp ) { < Metoden over skal øke saldoen på kortet med det beløpet som parameteren angir og oppdatere datafeltet sumAlleKlippekort. > } } // end of class Klippekortb) Programmer klassens konstruktør og alle get-metodene. c) Programmer metodene
public boolean gyldig()
og public void ladOpp( int beløp )
.
Klassene Dagskort
og Månedskort
skal ikke programmeres, men
du vil få bruk for dem senere i oppgaven. Et dagskort er gyldig som billett i 24 timer etter at
det er opprettet, mens et månedskort er gyldig i 30 dager etter opprettelsen.
Du trenger ikke å vite noe om hvordan klassene
er implementert, men du må vite hva metodene gjør, hvilke parametere de har og hva de returnerer.
Nedenfor ser du skisser av klassene, med deres public
datafelt og metoder.
public class Dagskort < arver Reisekort > { public final static int DAGSPRIS = 75; < private datafelt > public Dagskort() { ... } public static int getSumAlleDagskort() { ... } public static int getAntallSolgte() { ... } public boolean gyldig() { ... } // redefinert } // end of class Dagskort
public class Månedskort < arver Reisekort > { public final static int MÅNEDSPRIS = 1040; < private datafelt > public Månedskort() { ... } public static int getSumAlleMånedskort() { ... } public static int getAntallSolgte() { ... } public boolean gyldig() { ... } // redefinert } // end of class Månedskort
ReisekortSystem
, som er skissert nedenfor, lagrer alle reisekortene i en array.
I utgangspunktet er det plass til 100 reisekort. Arrayens størrelse skal imidlertid
kunne økes etter behov slik at salget av reisekort ikke begrenses. Nedenfor ser du en
skisse av klassen:
public class ReisekortSystem { public static final int = ANTALL 100; public static final int UTVIDELSE = 10; private Reisekort[] reisekortene; public ReisekortSystem() { < Oppretter arrayen med lengde lik ANTALL. > } public Reisekort finnReisekort(int nr) { < Metoden skal returnere (en referanse/peker til) det reisekortet i arrayen som har kortNr lik den innkomne parameteren nr. Hvis kortet ikke finnes i arrayen, skal metoden returnere null.> } public void utvidArray() { < Metoden skal utvide arrayen med så mange elementer som konstanten UTVIDELSE angir. Metoden vil bli kalt når det er behov for å utvide arrayen i forbindelse med innsetting av et nytt reisekort. > } public void settInnReisekort(Reisekort k) { < Metoden mottar et nytt reisekort som parameter og skal sette dette inn på første ledige plass i arrayen, under forutsetning av at det ikke finnes et reisekort med samme nr i arrayen fra før. Hvis arrayen er full, skal den først utvides med så mange elementer som konstanten UTVIDELSE angir, og deretter skal kortet settes inn. > } public Klippekort ladOppKlippekort( int nr, int beløp ) { < Hvis det finnes et klippekort med kortNr lik den innkomne parameteren nr, skal metoden øke saldoen på dette kortet med så mye som parameteren beløp angir, og deretter returnere (en referanse/peker til) klippekortet. Hvis det ikke finnes et slikt klippekort, skal metoden returnere null. > }
public static String inntjeningsInfo() { < Metoden skal returnere en tekst som inneholder informasjon om hvor mange reisekort det er solgt av de forskjellige typene, hvor mye som er tjent inn på hver type, og hvor mye som er tjent inn totalt. > } } // end of class ReisekortSystema) Programmer klassens konstruktør og metoden
public Reisekort finnReisekort(int nr)
.
b) Programmer metoden public void utvidArray()
.
c) Programmer metoden public void settInnReisekort(Reisekort k)
.
d) Programmer metoden public Klippekort ladOppKlippekort( int nr, int beløp )
.
e) Programmer metoden public static String inntjeningsInfo()
.
Administrasjonsvindu
, slik at vinduet
blir seende ut som på bildet. Klassen skal være sin egen lytteklasse og programmeres slik
at når du klikker på knappen "Salgsinformasjon" blir den informasjonen som returneres fra
inntjeningsInfo()
-metoden i klassen ReisekortSystem
vist i tekstområdet.
Nedenfor ser du en skisse av klassen Kontrollvindu
:
< import-setninger > public class Kontrollvindu < ... > { private JTextField kortIdFelt; private JTextArea display; private JButton kontroll; private ReisekortSystem kortsystem; public Kontrollvindu(ReisekortSystem r) { < kaller superklassens konstruktør > kortsystem = r; < oppretter lytteobjekt og knytter knappen til det. > < setter opp brukergrensesnittet > } public void kontrollerReisekort() { < Metoden må lese inn kortets nummer og sjekke om det finnes blandt de registrerte kortene. Hvis det finnes og det er gyldig, skal følgende gjøre: - Hvis det er et klippekort, skal prisen for en reise trekkes fra saldoen på kortet. Deretter skal det skrives ut i tekstområde hva reisen koster, hva som er saldoen etter at reisen er betalt og hvor lenge billetten varer. - Hvis det er et dagskort eller et månedskort skal det kun skrives ut hvor lenge billetten varer. Hvis kortet er ugyldig, skal dette skrives i tekstområdet. For klippekort skal i tillegg saldoen skrives ut. Hvis kortet er ukjent, skal dette skrives i tekstområdet.> } < privat lytteklasse > } // end of class Kontrollvindua) Programmer metoden
public void kontrollerReisekort()
Reisekortsalg
.
Denne klassen brukes til salg av reisekort og opplading av klippekort.
< import-setninger > public class Reisekortsalg < ... > { private static final int KLIPP = 1, DAG = 2, MÅNED = 3; private JTextField kortNrFelt, betalingsFelt, beløpsFelt; private JButton klipp, dag, mnd, ladeknapp; private JTextArea info; private Lytter lytter; private ReisekortSystem kortsystem; public Reisekortsalg(ReisekortSystem k) { super("KORTSALG"); kortsystem = k; lytter = new Lytter(); < oppretter skjermkomponenene > klipp.addActionListener(lytter); dag.addActionListener(lytter); mnd.addActionListener(lytter); ladeknapp.addActionListener( lytter ); < setter opp brukergrensesnittet. > } public void nyttReisekort(int type) { < Metoden skal foreta et salg av et reisekort av typen parameteren type angir. (Se konstantene i skissen av klassen over.) Når kortet er opprettet og satt inn i datasystemet, skal metoden skrive ut kortets nummer i tekstfeltet kortNrFelt og prisen som skal betales i tekstfeltet betalingsFelt. > } public void ladOppKlippekort() { < Metoden skal lade opp klippekortet med det beløpet som brukeren skriver inn, under forutsetning av at kortnummerer som oppgis tilhører et klippekort i datasystemet. I så fall skal den nye saldoen skrives ut i et dialogvindu (JOptionPane.showMessageDialog(..)), og prisen som skal betales skrives i betalingsfeltet. Hvis kortnummeret er feil skal det skrives "error" i betalingsfeltet. > } < privat lytteklasse > } // end of class Reisekortsalga) Programmer metoden
public void nyttReisekort(int type)
.
b) Programmer metoden public void ladOppKlippekort()
.
c) Programmer den private lytteklassen slik at den fanger opp klikkene på knappene
og sørger at riktig oppgave blir utført.
RuterPluss
. Klassen skal inneholde main-metoden,
der programutførelsen starter.