Les gjennom hele oppgavesettet før du begynner å besvare deloppgavene.

 

 

 

Ruter#PLUSS

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 superklassen Reisekort, 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.
De enkelte deloppgavene inneholder nærmere informasjon.

Oppgave 1

For å reise med Ruter#PLUSS må man ha et reisekort. Dette kortet er enten et 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 Reisekort 

a) 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 Klippekort

b) 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

Oppgave 2

Klassen 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 ReisekortSystem

a) 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().

Oppgave 3

Nedenfor ser du et bilde av administrasjonsvinduet:

a) Programmer vindusklassen 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.

Oppgave 4

På bilde under ser du brukergrensesnittet til den klassen som simulerer billettkontrollen, og det er her reisekortene valideres før hver reise.

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 Kontrollvindu

a) Programmer metoden public void kontrollerReisekort()

Oppgave 5

På bilde under ser du brukergrensesnittet til klassen Reisekortsalg. Denne klassen brukes til salg av reisekort og opplading av klippekort.

Nedenfor ser du en skisse av klassen:

< 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 Reisekortsalg

a) 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.

Oppgave 6

a) Programmer driverklassen RuterPluss. Klassen skal inneholde main-metoden, der programutførelsen starter.

SLUTT