Kodeskjelettet til venstre er det samme for alle deloppgavene. Det er markert hvilke metoder og klasser som skal implementeres i hvilke deloppgaver. De kan også endres i andre deloppgaver basert på dine egne kodevalg.
Temaet for oppgaven er administrasjon av sykkelutleie. Sykkelutleietjenesten (BikeRental) tilbyr leie av sykler (Bike) som plukkes opp og settes tilbake på utvalgte stasjoner spredt rundt omkring. (Senere oppgaver legger opp til at en kan leie ut andre fremkomstmidler også). Syklene har GPS, slik at de hele tiden spores (GeoLocation). Den som skal leie sykkel (Person) bruker en app for å få oversikt over hvor (ved hvilke stasjoner) det er tilgjengelige sykler. Deretter er det bare å identifisere sykkelen, angi hvor lenge man ønsker å leie den, og en kan sykle av gårde. Når en er ferdig med å bruke sykkelen, må den settes tilbake på en stasjon (ikke nødvendigvis den samme som en tok den fra). Ved hjelp av appen angir man at leieforholdet er avsluttet. Leieprisen blir da beregnet og pengene trukket.
Prisen er basert på påbegynte timer, og merk at en ikke betaler for mer enn faktisk bruk. Hvis man altså angir at en ønsker å leie en sykkel i tre timer, men leverer den tilbake etter en halv time, så betaler en for én times bruk. Det er mulig å utvide leietiden underveis, noe som utløser et lite gebyr. Hvis en utvider leietiden eller leverer sykkelen etter at sykkelen skulle vært levert, så påløper det også et gebyr.
Del 1 av oppgaven fokuserer på administrasjon av leieforholdet. I første omgang beregnes pris kun fra tidsbruk, mens i del 2 utvides det med gebyrer og kvittering. Del 3 fokuserer på å gjøre det lettere å bytte måten prisen beregnes. Del 4 handler om mobil-appen og del 5 om testing.
Expand | |||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||
BikeRental-klassen administrerer stasjonene, syklene og utleieforhold. Vi gjør det enkelt og identifiserer stasjonene med et geografisk punkt (GeoLocation, se skjelettet), altså lengde- og breddegrad. GeoLocation brukes også for lagring av posisjonen til syklene. Oppgave 1 a) - GeoLocationGeoLocation er kodet slik at instansene ikke kan endres. Hva er fordelen med dette?
Oppgave b) - GeoLocationSkriv ferdig double distance(GeoLocation)-metoden i GeoLocation.
Oppgave c) - BikeBike-klassen skal ha assosiasjoner (koblinger) til Person- (se skjelettet) og GeoLocation-klassene iht. følgende klassediagram. (Location i bildet over skulle hett GeoLocation, men det var tydelig nok i forhold til teksten hva som er ment.) Begge disse assosiasjonene er dynamiske, dvs. både location og renter (låntaker) kan endres. location-koblingen endres (automagisk, du kan bare forholde deg til at location hele tiden oppdateres) når sykkelen beveger seg, mens renter-koblingen endres når leieforhold innledes og avsluttes. Skriv felt og metoder for location- og renter-assosiasjonene iht. Java sine kodingskonvensjoner.
|
Gammel eksamen lagt inn som mal. Mer kommer!
Expand | ||
---|---|---|
| ||
Expand | | |
|
Code Block |
---|
/**
* Represents a set of die values.
*/
public class Dice implements Iterable<Integer> {
/**
* Counters for each possible die value.
* The counter at index i (0-5) is the counter for the die value i+1 (1-6).
* I.e. the value at index 2 is the counter for die value 3.
*/
private final int[] valueCounters;
/**
* Initializes this Dice with the values in dieValues.
* @param dieValues sequence of die values, not counter values
*/
public Dice(Iterator<Integer> dieValues) {
???
}
/**
* Initializes this Dice with the values in dieValues.
* @param dieValues sequence of die values, not counter values
*/
public Dice(Iterable<Integer> dieValues) {
???
}
@Override
public Iterator<Integer> iterator() {
return new DiceIterator(this);
}
/**
* @return the number of die values
*/
public int getDieCount() {
???
}
/**
* Die values are considered ordered, with the smallest die values
* at the lowest index. The value at a specific index
* must be computed from the counters in valueCounters.
* @param dieNum
* @return the value of die number dieNum
* @throws an appropriate exception, if dieNum is out of range
*/
public int getDieValue(int dieNum) {
???
}
/**
* @param value
* @return the number of dice with the provided value
*/
public int getValueCount(int value) {
???
}
/**
* @param dice
* @return true if all die values in the Dice argument appear in this Dice
*/
public boolean contains(Dice dice) {
???
}
/**
* @param dice
* @return true if this Dice and the one provided have exactly the same die values
*/
public boolean isSame(Dice dice) {
???
}
/**
* @param dice a Dice object
* @return a new Dice instance with the all the die values in
* this Dice and the Dice argument combined
*/
public Dice add(Dice dice) {
???
}
/**
* @param dice
* @return a new Dice instance with the die values from this Dice, but
* without those from the Dice argument
*/
public Dice remove(Dice dice) {
???
}
} |
Oppgave a) - Konstruktører (8 poeng)
Skriv kode for de to konstruktørene (merk forskjellen i argumenttype), slik at valueCounters blir riktig initialisert. Du SKAL IKKE innføre andre felt. Du kan lage hjelpemetoder om du ønsker. For begge konstruktørene er argumentet en sekvens med terningverdier (altså ikke tellere) som den nyinitialiserte instansen skal representere.
Merk at det er lov å lage ekstra konstruktører for å gjøre andre metoder, f.eks. add og remove, enklere å skrive.
Expand | ||
---|---|---|
| ||
Her er poenget å skjønne hvordan tabeller virker (opprettes, leses fra og skrives til) og logikken bak valueCounters-feltet, samt hvordan iterere med Iterator (hasNext() og next()) og Iterable (iterator()).
Vanlige feil: En del skrev kode som om de skulle lagre enkeltverdiene, ikke tellerne for hver mulig verdi. Da blir løsningen som på den ordinære eksamen, og det gir ikke uttelling. |
Oppgave b) - Terningverdier (8 poeng)
Skriv metodene getDieCount, getDieValue og getValueCount iht. forklaringen og koden gitt tidligere (API-beskrivelsen).
Expand | ||
---|---|---|
| ||
Når en først har tellerne i valueCounters, så er getDieCount- og getValueCount-metodene trivielle. getDieValue er litt mer kinkig, da en må beregne hvilket tall som vil falle på en bestemt indeks, uten noen liste over alle terningverdiene.
Vanlige feil: Det var en del som ikke skjønte hva metodene skulle gjøre, selv om det var de samme metodene som på ordinær eksamen. De må imidlertid skrives annerledes, siden terningene er representert på en annen måte.
|
Oppgave c) - Flere metoder (8 poeng)
Skriv metodene contains, isSame, add og remove, som alle tar et Dice-objekt som eneste argument. Merk at ingen av disse endrer på verken this-objektet eller argumentet.
Her er noen eksempler på bruken av disse metodene, hvor [t1, t2, t3, ... tn] brukes som pseudo-synaks for et Dice-objekt som representerer terningverdiene t1-tn:
[1, 2, 2, 4].contains([1, 4]) returnerer true, mens
[1, 2, 4].contains([2, 2]) returnerer false.
[1, 2, 2, 4].isSame([1, 2, 2, 4]) returnerer true, mens
[1, 2, 2, 4].isSame([1, 2, 4]) returnerer false
[1, 2].add([1, 4]) returnerer [1, 1, 2, 4]
[1, 1, 2].remove([1, 4]) returnerer [1, 2]
Merk at removei kke har samme logikk som Collectionsin removeAll-metode.
Expand | ||
---|---|---|
| ||
Disse metodene kan forsåvidt skrives kun vha. getDieValue-metoden og konstruktørene (som de fleste gjorde på den ordinære eksamenen), men det er mye enklere å utnytte at vi representerer terningene med tellere. Her utnytter vi også at vi kan lage tomme Dice-instanser, og så etterpå justere tellerne i valueCounters.
Vanlige feil:
|
Oppgave d) - DiceIterator (6 poeng)
Lag en implementasjon av Iterator<Integer>kalt DiceIterator, slik at den kan brukes slik det er vist i Dice sin iterator()-metode. Du kan anta at valueCounters-feltet i Dice er synlig i DiceIterator-klassen.
Expand | ||
---|---|---|
| ||
Trikset her er å skjønne at terningverdiene skal komme i samme rekkefølge som det en får fra getDieValue med stigende indekser. Her blir altså logikken helt uavhengig av hvordan terningsverdiene er representert internt i Dice-klassen.
Vanlige feil:
|
...