Denne siden er under arbeid.
Kodeskjelettet under
...
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.
KIldekoden som ble brukt under utvikling av oppgavene finner du på GitHub.
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? Expand | | ||||||||
| |||||||||
Code Block |
Expand | ||
---|---|---|
| ||
public class GeoLocationPerson {// Slettet gettere og settere etc.
// Kode for 1b
public double distance(final GeoLocation other) {
...
}
// Under følger kode for metoden dere kunne forvente at eksisterte.
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: /** * Withdraws the provided amount from this person's account. * If the transaction couldn't be completed, i.e. no money was actually withdrawn, * one of the indicated exceptions will be thrown. * @param amount the amount to withdraw * @throws IllegalArgumentException * @throws IllegalStateException */ public void withdraw(double amount) throws IllegalArgumentException, IllegalStateException { // ... } } public class GeoLocation { private final double latitude; private final double longitude; public GeoLocation(double latitude, double longitude):*/ {/*:: This routine calculates the distancethis.latitudebetween =two latitude;points (given the :*/
/*:: latitude/longitude of those points). It is being used to calculate :*/
/*:: the distance between two locations using GeoDataSource (TM) prodducts :*/
/*:: this.longitude = longitude; } public double getLatitude() { return latitude; } public double getLongitude() { return longitude; } /** * Computes distance to other Location * @param other * @return distance to other Location */ public double distance(GeoLocation other) { distance(this.latitude,this.longitude,other.):*/ /*:: Definitions:// ??? 1 b) } /** calculates the distance between two points, * given the latitude/longitude of those points).:*/ /*:: South latitudes are negative, eastlongitudes are positive*: */
/*::public static double distance(double lat1, double lon1, double lat2, double lon2) { // return null er bare tull, den har egentlig beregning her. return null; // Denne kompliserte beregningen er utelatt. // Anta at den er implementert. } } public class Bike {:* ///*:: Passed to function: ??? 1 c) } public class BikeRental { // ??? 1 d) /** * Counts the number of available bikes within a certain distance of a provided location. * @param location * @param distance: * /
/*:: lat1, lon1 = Latitude and Longitude of point 1 (in decimal degrees) :*/
/*:: lat2, lon2 = Latitude and Longitude of point 2 (in decimal degrees) :*/
/*:: Worldwide cities and other features databases with latitude longitude :*/
/*:: are available at http://www.geodatasource.com :*/
/*:: @return the number of available bikes within a certain distance of a provided location */ private int countAvailableBikesNearby(GeoLocation location, double distance) { // ??? 1 e) } /** * Finds the closest station (location) within the provided (maximum) distance of the provided bike * @param bike * @param minDistance * @return the closest station (location) within the provided (maximum) distance of the provided bike */ private GeoLocation getStationNearby(Bike bike, double maxDistance) { // ??? 1 e) } /** * @return the bikes that currently are rented:* *//*:: For enquiries,privateplease Collection<Bike>contact sales@geodatasource.com getRentedBikes() { // ??? 1 e) }:*/ /* ::* * @return the bikes that are close to a station (within 30m), but still are rented */ private Collection<Bike> getUnreturnedBikes() { // ??? 1 e) } /** * Called when a person starts renting a bike by taking it from:*/ a station./*:: Official Web site: http://www.geodatasource.com * Checks the arguments before registering all necessary info of the rental. * @param person: * /
/*:: @param now the start time of the rental * @param returnTime the expected return time * @throws (some subclass of) RuntimeException if the now isn't before returnTime * @throws (some subclass of) RuntimeException if the bike isn't available for rental */ public void rentBike(Person person, Bike bike, LocalDateTime now, LocalDateTime returnTime) {:*/ /*::// ??? 1 f) }GeoDataSource.com (C) All Rights/**Reserved 2015* Called when a person extends an ongoing bike rental.:*/ /*:: * Checks the arguments before registering all necessary info of the rental extension. * @param person * @param bike * @param now the time the extension starts * @param returnTime the (new) expected return time * @throws (some subclass of) RuntimeException if the now isn't before returnTime * @throws (some subclass of) RuntimeException:*/ /*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ public static double distance(final double lat1, final double lon1, final double lat2, final double lon2) { final double theta = lon1 - lon2; double dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta)); dist = Math.acos(dist); // convert to degrees dist = rad2deg(dist); dist = dist * 60 * 1.1515; // convert to meters dist = dist * 1609.344; return dist; } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:: This function converts decimal degrees to radians :*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ private static double deg2rad(final double deg) { return (deg * Math.PI / 180.0); } /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ /*:: This function converts radians to decimal degrees :*/ /*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/ private static double rad2deg(final double rad) { return (rad * 180 / Math.PI); } } 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) - Bike
Bike-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.
Expand | ||
---|---|---|
| ||
Her var det snakk om å velge en representasjonsmåte for en GeoLocation og en Person, samt lage gettere og settere. Skjule verdiene.
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.
if the bike isn't currently being rented
* @throws (some subclass of) RuntimeException if person isn't currently renting the bike
*/
public void extendRental(Person person, Bike bike, LocalDateTime now, LocalDateTime returnTime) {
// ??? 2 b)
}
/**
* Called when a person returns a bike.
* Checks the arguments, computes the price, performs the payment and clears the rental info.
* Note that if the payment isn't completed, the rental info should not be cleared.
* @param person
* @param bike
* @param now the time the bike is returned
* @throws (some subclass of) RuntimeException if the bike isn't currently being rented by the person argument
* @throws (some subclass of) RuntimeException if person isn't near (within 30m of) a station
*/
public void returnBike(Person person, Bike bike, LocalDateTime now) {
// ??? 1 f)
}
/**
* Called when the Person has returned a Bike.
* Displays initial rent period
* Displays extensions of the rent period
* Computes and displays total cost, including fees for late return.
* @param person
* @param bike
*/
void printReceipt(Person person, Bike bike) {
}
}
// Kontroller-logikk
// refers to the app's BikeRental object
private final BikeRental bikeRental;
// refers to the app user
private final Person me;
// refers to currently selected bike in map
private Bike bike;
??? 4 a, b)
/**
* @return a LocalDataTime object corresponding to the from input field value
*/
private LocalDateTime getFromTime() {
??? 4 b)
}
/**
* Updates the from input field value according to the LocalDateTime argument
* @param time
*/
private void setFromTime(final LocalDateTime time) {
??? 4 b)
}
/**
* @return a LocalDataTime object corresponding to the from input field value
*/
private LocalDateTime getToTime() {
??? 4 b)
}
/**
* Updates the from input field value according to the LocalDateTime argument
* @param time
*/
private void setToTime(final LocalDateTime time) {
??? 4 b)
}
// Husk kvittering.
Kvitteringsformat
Anta følgende sekvens av hendelser: / Presume the following sequence of events:
1 - En person leier en sykkel kl. 12:10 og angir at den skal returneres kl. 14:20.
1 - A persons rents a bike at 12:10 and specifies the return time to 14:20.
2 - Kl. 14:30 utvides leietiden til 15:10 (Merk forsinkelsen)
2 - At 14:30 the rent period is extended to 15:10. Mind the delay in extension.
3 - Kl. 15:15 leveres sykkelen
3 - 15:15: The bike is delivered.
Dette gir totalt 4 påbegynte timer = 4 * 10 kr,
1 utvidelse = 5 kr og 2 forsentkomminger = 2 * 10 kr.
Kvitteringen skal da se ut som følger: The receipt should look as follows:
Initial rental from 12:10 to 14:20
Extension 1 from 14:30 to 15:10
Bike returned at 15:15
Total cost: 65 kr,-
|
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 1b) - GeoLocationSkriv ferdig double distance(GeoLocation)-metoden i GeoLocation.
Oppgave 1c) - BikeBike-klassen skal ha assosiasjoner (koblinger) til Person- (se skjelettet) og GeoLocation-klassene iht. følgende klassediagram.
(Location 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.
Oppgave 1d) - BikeRentalBikeRental må holde oversikt over alle stasjonene, representert med GeoLocation, og alle syklene (Bike). Skriv nødvendige variabel-deklarasjoner (felt) for dette og forklar hva som styrer valget av typer. Du skal ikke skrive metoder for å konfigurere systemet med stasjoner og sykler, men anta at slike finnes.
Beskrivelse av oppgavene 1e og 1fI første omgang skal du skrive forenklet kode for leie og retur av sykler, hvor det ikke tas hensyn til annet enn start- og slutt-tidspunkt for leieforholdet. Forlenging av leie ser vi foreløpig bort fra. renter-assosiasjonen i Bike skal holde rede på hvem (Person) som evt. leier en sykkel (Bike). Du bestemmer selv hvor/hvordan du vil representere når leieforholdet starter og når det forventes at sykkelen leveres tilbake. Det viktigste er at informasjonen kan brukes når sykkelen leveres og leien skal beregnes og betales. Oppgave 1e) - BikeRentalSkriv metodene under i klassen BikeRental (se skjelettet til venstre for detaljene). Disse metodene bygger på representasjonen du valgte i 1d.
Oppgave 1f) - BikeRental (mer)Skriv metodene rentBike og returnBike i klassen BikeRental (se skjelettet for detaljene, merk spesielt krav om utløsing av unntak). Disse metodene endrer tilstanden som brukes av de foregående metodene. Velg selv passende unntakstype(r). LocalDateTime brukes for å representere tid (erstatter Date i moderne Java). Gjør nødvendige antakelser om metoder den har, som trengs for tidsberegninger, og bruk disse antakelsene.
|
Expand | ||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||||||||||||||||
BikeRental-klassen skal utvides til å støtte forlengelse av leie, beregning av gebyrer for forlengelse og for å forlenge eller levere tilbake sykkelen etter angitt tid. I tillegg skal det lagres nok data om dette, så en kan få skrevet ut en kvittering med forklaring på hvordan prisen framkom. Oppgave 2a)Forklar med tekst og/eller kode hvordan du vil lagre informasjon om evt. forlengelser av leieforholdet, slik at systemet har nok informasjon til å kunne
Oppgave 2b)Gjør nødvendige endringer av rentBike- og returnBike-metodene i BikeRental, iht. de nye kravene nevnt over, og skriv i tillegg extendRental-metoden. Baser deg på en pris på 10 kr. pr. påbegynte time (som over), 5 kr. pr. forlengelse og 10 kr. pr. for sen forlengelse eller tilbakelevering.
Oppgave 2c)Skriv metoden printReceipt i BikeRental, som kan kalles av returnBike for å skrive ut kvitteringen iht. formatet gitt nederst i skjelettet til venstre. Vær obs på at det eksisterer en metode formatLocalDateTime i skjelettet, som kan hjelpe.
|
Expand | |||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||||||
Koden for beregning av pris er til nå hardkodet i BikeRental-klassen. Dette er noe det kan være greit å kunne endre på, f.eks. hvis en introduserer abonnement, eller man kan introdusere ulike typer fremkomstmidler med hver sin pris. Koden bør dermed gjøres mer fleksibel. Teknikken du skal bruke er delegering. Oppgave 3a)Forklar med tekst og/eller kode hvordan du kan bruke delegering for å gjøre det enklere å bytte ut strategien (beregningslogikken) for prising (globalt). Få med hvordan prisberegningslogikken fra tidligere blir en del av den nye løsningen. Hvis du ikke har fått til del 2 kan du bygge på løsningen fra del 1.
Oppgave 3b)Forklar med tekst og kode hvordan en også kan bruke delegering for å tilby individuell prising (altså pr. Person), f.eks. bonus-ordninger.
Oppgave 3c)En antar at det finnes ulike klasser for ulike typer fremkomstmidler en kan leie. Hver type skal kunne ha sine egne sett med verdier brukt til prising, f.eks. pris pr. time og pris pr. tidsforlengelse. Forklar med tekst og/eller kode hvordan du kan håndtere dette, og spesielt hvordan arvingsmekanismen kan benyttes.
|
Expand | |||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||
Under ser du et utkast til en mobil-app for sykkelutleietjenesten, basert på FXML. Kartet til venstre viser hvor det er sykler, og én stasjon er valgt (og implisitt også en sykkel på stasjonen). Brukeren kan endre antatt tidspunkt for tilbakelevering ved å endre teksten i tekstfeltet eller bruke knappene til høyre for feltet. Den vesentlige (for denne oppgaven) FXML-koden er vist til høyre.
Oppgave 4a)Gitt denne FXML-koden, hvilke kode-elementer (klasser, felt og metoder) må finnes i koden som implementerer oppførselen (logikken) til appen?
Oppgave 4b)I kodeskjelettet er ufullstendig kode for oppførselen til appen angitt (kontroller-logikk). Fyll ut de manglende kodeelementene, som angitt i kommentarer eller markert med ??? Det er lov å anta at LocalDateTime-klassen har konstruktør og metode for konvertering fra og til String, samt metoder for å lage nye LocalDateTime-instanser et gitt antall sekunder før og etter.
|
Expand | ||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||||||||||||||
Oppgave 5a)Skriv kode som tester getRentedBikes i BikeRentalsom vist i skjelettet til venstre (og som ble løst i oppgave 1e). Gjør nødvendige antakelser om metoder som brukes til konfigurasjon av BikeRental.
Oppgave 5b)Forklar med tekst og/eller kode hvorfor det er mer komplisert å teste rentBike og returnBike enn å teste getRentedBikes. Hvilke aspekter ved disse metodene er det som gjør det mer komplisert?
|