Skip to content
Snippets Groups Projects
Commit 9d7bd6e1 authored by Andreas Omholt Olsen's avatar Andreas Omholt Olsen
Browse files

Add oving7

parent 9a60574d
No related branches found
No related tags found
No related merge requests found
Showing
with 823 additions and 1 deletion
......@@ -11,3 +11,4 @@ Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmeri
| [Øving 4](./oving4/README.md) | Objektstrukturer |
| [Øving 5](./oving5/README.md) | Grensesnitt |
| [Øving 6](./oving6/README.md) | Observatør-observert og delegering |
| [Øving 7](./oving7/README.md) | Arv og abstrakte klasser |
\ No newline at end of file
# Arv - AbstractAccount-oppgave
Denne oppgaven handler om å lage en felles abstrakt superklasse `AbstractAccount`
for `CreditAccount`, `DebitAccount`- og `SavingsAccount2`-klassene.
Denne oppgaven er en annen variant av
[SavingsAccount](./SavingsAccount.md)-oppgaven, med fokus
på bruk av abstrakte klasser og arv.
### Del 1 - Abstrakt klasse AbstractAccount
En bank består av mange ulike type kontoer: sparekontoer, brukskontoer,
depositumskontoer, støttekontoer etc. Siden disse har mye felles, f.eks.
har alle en balanse, så er det praktisk å samle så mye som mulig av den
felles logikken i en superklasse, som alle kan arve fra. Denne superklassen
er imidlertid ikke noen egen type konto, og derfor gjør vi den abstrakt,
slik at den ikke kan instansieres. De konkrete konto-klassene som arver
fra den, må selvsagt være instansierbare.
Metodene i `AbstractAccount`-klassen, er omtrent de samme som dem vi definerte
i `Account`-grensesnittet i [SavingsAccount](./SavingsAccount.md)-oppgaven,
og er som følger:
* `void deposit(double)` - øker kontobalansen med innskutt beløp. Merk at det
innskutte beløpet må være positivt. Ved ulovlig innskudd skal en
`IllegalArgumentException` utløses.
* `void withdraw(double)` - Metoden kaller <code>internalWithdraw(<i>uttaksbeløp</i>)</code>,
som implementeres i hver subklasse. Hvis uttaksbeløpet er negativt skal
metoden utløse en `IllegalArgumentException`.
* `abstract void internalWithdraw(double)` - minsker kontobalansen med beløpet
som blir tatt ut. Merk at reglene for uttak er ulik for klassene som
implementerer `AbstractAccount`, og må derfor implementeres i hver klasse.
Hvis det ikke er mulig å ta ut det angitte beløpet skal metoden utløse en
`IllegalStateException`.
* `double getBalance()` - returnerer kontobalansen.
Alle metodene utenom den absktrakte må implementeres. I tillegg må
`AbstractAccount` ha en tilstand *balance* for saldo på kontoen.
Saldoen skal settes til 0 i konstruktøren.
Vær oppmerksom på at du i Del 2 skal lage subklasser av `AbstractAccount`
og at du ved å bruke rett innkapsling (hint: `protected`-modifikatoren) skal
la *subklassene* nyttiggjøre seg *superklassen* i størst mulig grad.
### Del 2 - DebitAccount extends AbstractAccount
En debetkonto er den enkleste formen for konto, hvor det eneste kravet er at
saldoen til enhver tid må være større eller lik 0. `DebitAccount` skal utvide
(arve fra med `extends`) `AbstractAccount` og sikre at saldoen aldri blir
lavere enn 0.
Testkode for oppgavene finner du her: [oving7/DebitAccountTest.java](../../src/test/java/oving7/DebitAccountTest.java).
### Del 3 - CreditAccount extends AbstractAccount
En `CreditAccount` har i tillegg til *balance* en tilstand for *creditLine*,
altså tilgjengelig kreditt på kontoen. Denne kredittlinjen tillater at kontoen
kan overtrekkes (at saldoen er negativ) innenfor kredittlinjen. Klassen må ha
*tilgangsmetoder* (getters and setters) for *creditLine*. Merk at
kredittlinjen alltid må være større eller lik 0, hvis ikke skal det utløses
en `IllegalArgumentException`. Hvis en ny kredittlinje settes og balansen er
negativ, må den nye kredittlinjen dekke den eksisterende balansen. Ellers skal
det utløses en `IllegalStateException` og ingen endring i kredittlinjen.
Konstruktøren `CreditAccount(double)` skal sette kredittlinjen.
Testkode for oppgavene finner du her: [oving7/CreditAccountTest.java](../../src/test/java/oving7/CreditAccountTest.java).
### Del 4 - SavingsAccount2 extends AbstractAccount
En `SavingsAccount2` (*merk at navnet er endret, for ikke å kræsje med
SavingsAccount-klassen fra den tidligere oppgaven!*) kan kun ha positiv saldo.
I tillegg har kontoen uttaksbegrensinger. En `SavingsAccount2` har *x* antall
*uttak* (**withdrawals**). Dersom man ønsker å ta ut penger etter alle uttak er
brukt opp, skal saldoen belastes med et *gebyr* (**fee**). Både **withdrawals**
(antall) og **fee** (beløp) settes i konstruktøren `SavingsAccount2(int, double)`.
Testkode for oppgavene finner du her: [oving7/SavingsAccount2Test.java](../../src/test/java/oving7/SavingsAccount2Test.java).
\ No newline at end of file
# Arv - CardContainerImpl-oppgave
Denne oppgaven handler om å lage en felles superklasse `CardContainerImpl`
for `CardDeck`- og `CardHand`-klassene, laget i [Card-oppgaven](../oving4/Card.md)
og [CardContainer-oppgaven](../oving5/CardContainer.md).
**Merk:** Om du ikke har gjort Card-oppgaven og CardContainer-oppgaven allerede,
kan du bruke filene som er lagt ved i øvingsmappen. Du kan bytte ut disse med din egen implementasjon om du ønsker.
### Del 1 - Superklassen CardContainerImpl
Lag en `CardContainerImpl`-superklasse, som implementerer grensesnittet
`CardContainer` (se [CardContainer-oppgaven](../oving5/CardContainer.md)) og
inneholder koden som er felles for `CardDeck` og `CardHand`.
La `CardDeck` og `CardHand` arve `CardContainerImpl` og gjør nødvendige endringer
i disse klassene, slik at totaloppførselen er som før. F.eks. skal `CardDeck`
-objektet ha samme konstruktør som før, som skal sikre samme initielle tilstand
(men ikke nødvendigvis med samme konstruktør-kode).
Merk at målet er at mest mulig kode skal flyttes til _superklassen_ og gjenbrukes
i _subklassene_. Det er viktig å bruke innkapsling rett
(hint: `protected`-modifikatoren) for å nyttiggjøre seg superklassen i størst
mulig grad.
### Del 2 - Regler for maksimalt antall kort
Anta at en ønsker å unngå at instanser av `CardContainerImpl` (eller av en av
subklassene) inneholder for mange kort. Legg til et _privat_ `maxCardCount`-felt
i `CardContainerImpl`, en konstruktør som _initialiserer_ feltet og en _getter_
for å lese verdien. Legg så til evt. endre kode i `CardContainerImpl` som sikrer
at antall kort ikke overstiger dette tallet og at subklassene ikke kan omgå
denne valideringen.
`CardContainerImpl`-subklassene `CardDeck` og `CardHand` skal sette maks-antallet
som følger: `CardDeck` skal sette makstallet til _52_ og `CardHand` skal ta
inn maks-antallet i _sin_ konstruktør. Hvis man forsøker å legge til flere kort
enn hva som er tillatt i `CardHand`, skal det utløses en `IllegalStateException`.
Testkode for oppgavene finner du her: [oving7/CardDeckTest.java](../../src/test/java/oving7/CardDeckTest.java) og [oving7/CardHandTest.java](../../src/test/java/oving7/CardHandTest.java).
# Observatør-observert-teknikken og arv - HighscoreList-oppgave med ObservableList
Denne oppgaven handler om å bruke observatør-observert-teknikken for å bli
informert om endringer i en highscore-liste. Vi bruker også arv for å skille
ut gjenbrukbar kode for en generell, observerbar liste.
Observatør-observert-teknikken går ut på at det observerte objektet sier ifra
til en eller flere observatører om at tilstanden er endret. I denne oppgaven
skal vi lage en `HighscoreList` som kan si fra til lyttere av typen
`ListListener` når nye resultater blir registrert. En hovedprogramklasse kalt
`HighscoreProgram` vil bli brukt til å sjekke at det virker. Denne klassen
oppretter en `HighscoreList`-instans, legger inn resultater (tall) fra
konsollet som legges til lista og skriver ut lista hver gang et nytt resultat
faktisk blir lagt til.
Klassene skal legges i `src/main/java/oving7/` og tilhørende
tester ligger i `src/test/java/oving7/`.
### Del 1: Implementasjon av ObservableList og ObservableHighscoreList
En `ObservableHighscoreList` skal holde styr på heltallsresultater (av typen
int/Integer). Lista skal være _observerbar_ ved at den kan registrere lyttere
(`ObservableListListener`-instanser) og si fra til dem når lista blir endret.
Lista skal ha en maksimal lengde, som settes i _konstruktøren_, f.eks. skal en
topp 10-liste kunne opprettes med `new ObservableHighscoreList(10)`.
Nye resultater registreres med metoden `addResult(int)`, som skal finne riktig
posisjon og legge resultatet inn (dersom det er godt nok). Dersom lista er for
lang, så skal det dårligste resultatet fjernes. NB: _Lavest verdi er best_,
f.eks. antall sekunder på en oppgave eller antall flytt i Sokoban.
`ObservableListListener`-grensesnittet er vist i klassediagrammet nedenfor og
må implementers av alle klasser som ønsker å fungere som lyttere for
`ObservableHighscoreList`-instanser. Lyttere registrerer seg med
`ObservableHighscoreList` sin `addObservableListListener`-metode og vil siden
få beskjed om nye resultater ved at `listChanged`-metoden kalles. Argumentene
som tas inn er `ObservableHighscoreList`-objektet som ble endret og _posisjonen_
i lista der endringen skjedde.
Merk at første argument til `listChanged`-metoden er av typen `ObservableList`.
Dette er en abstrakt superklasse for `ObservableHighscoreList`, som først
brukes i del 3 og som da skal holde orden på lista. `ObservableList` vil ha en
del generelle metoder som `ObservableHighscoreList` arver og kan bruke. For å
kunne kjøre testene for `ObservableHighscoreList` allerede i del 1, så må
`ObservableList` være definert fra starten. Lag derfor en tom
`ObservableList`-klasse og bruk denne som superklasse for
`ObservableHighscoreList`.
Her er en oversikt over metoden som må implementeres:
- `ObservableHighscoreList(int maxSize)` - konstruktøren tar inn _maks antall_
resultater som lista skal kunne holde. Denne verdien må brukes av `addResult`,
slik at resultater som er for dårlige kastes.
- `size()` - returnerer antall elementer i lista, som altså aldri skal
overstige maks-antallet
- `int getElement(int)` - returnerer resultatet i posisjonen angitt av
argumentet
- `void addResult(int)` - registrere et nytt resultat, og dersom resultatet er
godt nok til å komme med på lista, så legges det inn på riktig plass.
Dersom lista blir for lang, så må dårligste resultat kastes. Alle registrerte
lyttere må få beskjed om en evt. endring av lista, inkludert hvilken
posisjon som ble endret.
- `addObservableListListener(ObservableListListener)` - registrerer en ny lytter
- `removeObservableListListener(ObservableListListener)` - fjerner en tidligere
registrert lytter
Klassediagram for `HighscoreList`, `ListListener` og `ObservableList`:
<img src="images/ObservableList_del1.png" width="570">
Testkode for denne oppgaven finner du her: [oving7/ObservableHighscoreListTest.java](../../src/test/java/oving7/ObservableHighscoreListTest.java).
### Del 2: Hovedprogram ObservableHighscoreListProgram
Lag en hovedprogramklasse kalt `ObservableHighscoreListProgram`, som tester at
`ObservableHighscoreList`-klassen din virker som den skal. La den opprette en
`ObservableHighscoreList`-instans, lese inn tall fra konsollet (f.eks. med en
`Scanner` og `nextInt`-metoden) og legge disse inn i lista. Sørg for at
`ObservableHighscoreListProgram` implementerer
`ObservableListListener`-grensesnittet og registrerer seg som lytter på
`HighscoreList`-instansen. La lyttermetoden `listChanged` skrive ut informasjon
og resultatene i `HighscoreList`-instansen og posisjonsargumentet, slik at du
ser at alt virker som det skal.
Vi foreslår følgende metoder og oppførsel:
- `void init()` - oppretter en ny `ObservableHighscoreList` og registrerer seg
selv (altså `ObservableHighscoreListProgram`-instansen) som lytter
- `void run()` - leser inn tall (resultater) fra konsollet og legger dem til i
listen
- `void listChanged(ObservableList, int)` - observerer endringer i
`ObservableHighscoreList`-instansen og skriver ut posisjonsargumentet, samt
selve listen, til konsollet
Klassediagrammet viser hvordan klassene henger sammen, og vårt forslag til
metoder:
<img src="images/ObservableList_del2.png" width="670">
### Del 3: ObservableList
Den abstrakte superklassen `ObservableList` skal legges til som en generell
superklasse for observerbare lister, som `ObservableHighscoreList` skal arve
fra. Denne klassen skal både holde en liste med objekter (`Object`) og håndtere
registrering av lyttere, altså en liste med `ObservableListListener`-instanse,
som får beskjed om endringer i lista (slik at lista dermed er _observerbar_).
Dette betyr at `ObservableList` overtar håndtering av både resultater og
lyttere fra `ObservableHighscoreList`-klassen. For å gjøre `ObservableList` mer
generell og gjenbrukbar, så lar vi den håndtere `Object`-instanser (heller enn
`Integer`). Samtidig deklarerer den en _abstrakt_ metode `acceptsElement`, som
subklasser må _redefinere_ for å bestemme hva slags objekter det skal være lov
å legge inn. `ObservableHighscoreList` vil f.eks måtte redefinere den slik
at bare `Integer`-objekter aksepteres.
`ObservableList` skal ha følgende metoder (noen er altså overtatt fra
`ObservableHighscoreList`):
- `int size()` - returnerer antall elementer i lista
- `Object getElement(int)` - returnerer elementet i posisjonen angitt av
argumentet
- `abstract boolean acceptsElement(Object)` - returnerer hvorvidt _subklassen_
aksepterer at objektet legges inn i lista (f.eks. aksepterer `HighscoreList`
kun `Integer`-objekter).
- `void addElement(int, Object)` - legger til et element på posisjonen angitt
av argumentet, men bare dersom det _aksepteres_ som element. Dersom elementet
ikke aksepteres, så skal `IllegalArgumentException` utløses. Dersom posisjonen
er ulovlig så skal `IndexOutOfBoundsException` utløses.
- `void addElement(Object)` - legger til et element bakerst i lista, men bare
dersom det _aksepteres_ som element. Dersom elementet ikke aksepteres, så skal
`IllegalArgumentException` utløses.
- `void removeElement(int)` - fjerner elementet på posisjonen angitt av
argumentet. Dersom posisjonen er ulovlig så skal `IndexOutOfBoundsException`
utløses.
`ObservableHighscoreList` skal endres slik at den i størst mulig grad bruker
metodene som arves fra `ObservableList`, men forøvrig ikke endrer oppførsel.
Kjør hovedprogramklassen `ObservableHighscoreListProgram` for å sjekke at dette
faktisk stemmer.
Klassediagrammet viser hvordan klassene henger sammen, og hvor metodene nå er
deklarert/implementert. Merk at `addElement`- og `removeElement`-metodene er
angitt som `protected` (ruter-symbolet), slik at kun subklasser skal kunne
bruke dem.
<img src="images/ObservableList_del3.png" width="670">
Testkode for denne oppgaven finner du her: [oving7/ObservableListTest.java](../../src/test/java/oving7/ObservableListTest.java).
# Øving 07: Arv og abstrakte klasser
**Øvingsmål**
* Lære hvordan arv-mekansimen brukes i OO
* Lære om instanser, typer, deklarasjoner og tilordninger
* Lære om sub- og superklasser samt om synlighetsmodifikatorer som brukes ved arv
* Lære om abstrakte klasser, deres bruksområder og fordeler
**Øvingskrav**
* Kunne bruke arv til å modellerere enkle(re) objektstrukturer- og relasjoner i Java
* Kunne la flere subklasser bruke funksjonalitet definert i samme superklasse
* Kunne la en subklasse redefinere metoder definert i en superklasse
* Kunne samle felles oppførsel til to eller flere subklasser i en felles abstrakt klasse
## Dette må du gjøre
Oppgavene skal lagres i `ovinger/src/main/java/oving7`.
I begge delene er antageligvis vanskelighetsgraden stigende. Alle er høyst eksamensrelevante og det anbefales følgelig å ta en titt på samtlige.
For å få 2 poeng på øvingen må det gjennomføres til sammen *4* valgfrie oppgaver fra del 1 og 2.
### Del 1: Arv
Velg og gjennomfør *minst én* av oppgavene om arv:
* [CardContainerImpl](./CardContainerImpl.md)
* [Train](./Train.md)
* [SavingsAccount](./SavingsAccount.md)
### Del 2: Abstrakte klasser og arv
Velg og gjennomfør *minst én* av oppgavene om abstrakte klasser og arv:
* [AbstractAccount](./AbstractAccount.md)
* [ObservableList](./ObservableList.md)
### Hjelp / mistanke om bugs
Ved spørsmål eller behov for hjelp konsulter studassen din i saltiden hans / hennes. Du kan også oppsøke andre studasser på sal eller legge ut et innlegg på [Piazza](https://piazza.com/).
### Godkjenning
Last opp kildekode på Blackboard innen den angitte innleveringsfristen. Innlevert kode skal demonstreres for en læringsassistent innen én uke etter innleveringsfrist. Se for øvrig Blackboard-sidene for informasjon rundt organisering av øvingsopplegget og det tilhørende øvingsreglementet.
# Arv - SavingsAccount-oppgave
Denne oppgaven handler om å lage en felles superklasse `SavingsAccount` for
`BSU`- og `ForeldreSpar`-klassene. `SavingsAccount` skal dessuten implementere
`Account`-grensesnittet.
Denne oppgaven bygger videre på `Account`-oppgavene fra
[øving 2](../oving2/Account.md) og [øving 1](../oving1/Account.md).
### Del 1 - SavingsAccount implements Account
En bank består av mange ulike type kontoer: sparekontoer, brukskontoer,
depositumskontoer, støttekontoer etc. Felles for alle kontoer er
`Account`-grensesnittet, som er definert under:
```java
package oving7;
public interface Account {
public void deposit(double amount);
public void withdraw(double amount);
public double getBalance();
}
```
Vi skal i denne oppgaven fokusere på sparekontoer og du skal nå lage en
`SavingsAccount`-superklasse, som implementerer `Account`-grensesnittet.
Funksjonaliteten som hver av metodene definert i grensesnittet over skal
støtte er:
- `void deposit(double)` - øker kontobalansen med innskutt beløp. Merk at det
innskutte beløpet må være positivt. Ved ulovlig innskudd skal en
`IllegalArgumentException` utløses.
- `void withdraw(double)` - minsker kontobalansen med beløpet som blir tatt ut.
Merk at uttaksbeløpet må være positivt, ellers skal et unntak av typen
`IllegalArgumentException` utløses. Dersom det ikke er dekning på kontoen
(en `SavingsAccount` kan ikke ha negativ balanse) skal et unntak av typen
`IllegalStateException` utløses.
- `double getbalance()` - returnerer kontobalansen.
I tillegg til å støtte `Account`-grensesnittet over, som er felles for alle
kontoer, skal sparekontoer ha en rentefot og en metode som forrenter kontoen.
Denne kalles av bankene for hver sparekonto på slutten av året slik at alle
dets kunder opptjener renter (ikke tenk på at banker egentlig holder styr på
hvor stor balansen har vært gjennom hele året eller forrenter kontoen
kontinuerlig - her skal vi bare anta at innestående kontobalanse ved årsslutt
forrentes i sin helhet) - derfor heter metoden `endYearUpdate()`. I tillegg
skal `SavingsAccount`-klassen ha en konstruktør som tvinger alle objekter
av denne typen til å bli instansiert med en rentefot. Dette er oppsummert her:
- `SavingsAccount(double)` - konstruktør som tar inn rentefoten på kontoen
(et desimaltall, f.eks. 0.05 tilsvarer en rente på 5 %). Åpningsbalansen
skal være 0.
- `void endYearUpdate()` - forrenter kontobalansen basert på rentefoten.
Vi tenker oss at denne kalles av kode utenfor denne klassen, f.eks. resten
av et tenkt banksystem ved årsoppgjør, som et signal på at nå er et nytt år
over.
Vær oppmerksom på at du i Del 2 og 3 skal lage _subklasser_ av `SavingsAccount`
og at du ved å bruke rett innkapsling (hint: `protected`-modifikatoren) kan la
_subklassene_ nyttiggjøre seg _superklassen_ i størst mulig grad.
Testkode for oppgavene finner du her: [oving7/SavingsAccountTest.java](../../src/test/java/oving7/SavingsAccountTest.java).
### Del 2 - BSU extends SavingsAccount
I tillegg til generelle sparekontoer finnes det en spesiell type sparekonto
som heter BSU. Du skal nå lage en `BSU`-klasse som arver fra
`SavingsAccount`-superklassen. Her er målet at du skal gjenbruke mest mulig
av _superklassen_ og samtidig støtte BSU-spesifikk oppførsel. En BSU-konto er,
i tillegg til å være en sparekonto, spesiell i den forstand at det kun er
lovlig å sette inn inntil et forhåndsbestemt beløp per år
(den gamle regjeringen fastslo at BSU-kontoer i 2014 skulle ha en
innskuddsgrense på kr 25 000, men din kode skal ha støtte for å ha en vilkårlig
grense) og at det kun er lovlig å ta ut av det beløpet som er satt inn siste
år. M.a.o. vil en ved årsskifte få mulighet til å sette inn nye innskudd
innenfor innskuddsgrensen, men en har ikke lenger mulighet til å ta ut hele
balansen (innskudd fra tidligere år låses). Dessuten gir en vanlig BSU-konto
20% skattefradrag for årets innskudd.
Du må selv avgjøre hvilke felt som må legges til for å støtte den beskrevne
oppførsel. I tillegg stilles følgende krav til klassen:
- `BSU(double, double)` - konstruktør som tar inn rentefoten på kontoen og et
desimaltall som angir hvor mye det er tillatt å sette inn på kontoen per år.
- `double getTaxDeduction()` - returnerer skattefradrag for inneværende år.
Dette vil være 20% av innskutt(e) beløp siste år.
Testkode for oppgavene finner du her: [oving7/BSUTest.java](../../src/test/java/oving7/BSUTest.java).
### Del 3 - ForeldreSpar extends SavingsAccount
En annen spesiell type sparekonto, her kalt ForeldreSpar, har et begrenset
antall lovlige uttak per år (ofte i bytte mot en høyere rente). Du skal nå
lage en slik `ForeldreSpar`-klasse som arver fra `SavingsAccount`-superklassen.
Her er igjen målet at du skal gjenbruke mest mulig av _superklassen_ og
samtidig støtte ForeldreSpar-spesifikk oppførsel. Denne klassen skal sikre at
kun det lovlige antallet uttak gjøres i løpet av et år.
Du må selv avgjøre hvilke felt som må legges til før å støtte den beskrevne
oppførsel. I tillegg stilles følgende krav til klassen:
- `ForeldreSpar(double, int)` - konstruktør som tar inn rentefoten på kontoen
og et heltall som angir antall lovlige uttak per år.
- `int getRemainingWithdrawals()` - returnerer antall gjenstående uttak fra
sparekontoen.
Testkode for oppgavene finner du her: [oving7/ForeldreSparTest.java](../../src/test/java/oving7/ForeldreSparTest.java).
# Arv - Train-oppgave
I denne oppgaven skal vi modellere to typer togvogner og bruke dem i et tog. Vi vil bruke
arv og samle det som er felles for togvognene i en _superklasse_.
### Del 1 - TrainCar
<img src="images/Train_del1.png" width="170">
I denne delen skal du lage en klasse kalt `TrainCar` for en enkel og generell
togvogn, med følgende funksjonalitet (se også diagrammet over):
- `TrainCar(int)` - en konstruktør som tar inn hvor mye en tom vogn veier.
- `int getTotalWeight` - returnerer vognas totale vekt. Merk at denne også skal
kunne kalles på _subklasser_ og fortsatt returnere totalvekta til vogna
(stikkord: _redefinering_).
- `setDeadWeight(int)` - setter hvor mye en tom vogn veier. Altså vekten til
kun vognen, uten passasjerer eller last.
- `int getDeadWeight()` - returnerer hvor mye en tom vogn veier. Altså vekten til
kun vognen, uten passasjerer eller last.
Testkode for oppgaven finner du her: [oving7/TrainCarTest.java](../../src/test/java/oving7/TrainCarTest.java).
### Del 2 - CargoCar og PassengerCar
<img src="images/Train_del2.png" width="350">
I denne delen skal du lage to forskjellige typer togvogner som er spesialiserte
for sitt bruk. Begge skal arve fra `TrainCar`.
##### CargoCar extends TrainCar:
Denne klassen skal gjenspeile en lastevogn som frakter diverse ting og tang.
Følgende funksjonalitet trengs (se også diagrammet over):
- `CargoCar(int, int)` - her tas inn hvor mye en tom vogn veier (som i `TrainCar`),
og hvor mye vogna sin last veier.
- `int getCargoWeight()` - returnerer hvor mye lasten veier.
- `setCargoWeight(int)` - setter en ny verdi for vekten til lasten.
##### PassengerCar extends TrainCar:
Denne klassen gjenspeiler en passasjervogn. Legg til følgende metoder
(se også diagrammet over):
- `PassengerCar(int, int)` - her tas inn hvor mye en tom vogn veier
(som i `TrainCar`), og hvor mange passasjerer det er i vogna.
- `int getPassengerCount()` - returner antall passasjerer.
- `setPassengerCount(int)` - setter en ny verdi for antall passasjerer.
For å beregne totalvekta, så kan du anta at en gjennomsnittspassasjer veier 80 kg.
Testkode for oppgavene finner du her: [oving7/PassengerCarTest.java](../../src/test/java/oving7/PassengerCarTest.java) og [oving7/CargoCarTest.java](../../src/test/java/oving7/CargoCarTest.java).
### Del 3 - Train
<img src="images/Train_del3.png" width="450">
Klassen `Train` skal forestille et tog bestående av et sett vogner.
Klassen skal ha følgende metoder (se også diagrammet over):
- `addTrainCar(TrainCar)` - denne metoden skal ta inn en togvogn og knytte den
til dette lokomotivet.
- `boolean contains(TrainCar)` - Sjekker om lokomotivet har `TrainCar`-argument
knyttet til seg.
- `int getTotalWeight()` - returner alle vognene sin totale vekt. Vi tar ikke
høyde for lokomotivet sin eventuelle vekt.
- `int getPassengerCount()` - tilsvarende `PassengerCar` sin metode, men
returnerer antallet for alle vognene.
- `int getCargoWeight()` - tilsvarende `CargoCar` sin metode, men returnerer
lastevekten for alle vognene.
- `String toString()` - `toString`-metoden skal sette sammen en _String_ med
oversikt over alle vognene som er knyttet til den. For hver vogn skal vogntype
og totalvekt være med. Passasjervogner skal i tillegg ha med antall passasjerer
og lastevogner skal ha med hvor mye lasten veier.
Testkode for oppgaven finner du her: [oving7
/TrainTest.java](../../src/test/java/oving7/TrainTest.java).
ovinger/oppgavetekster/oving7/images/ObservableList_del1.png

81.2 KiB

ovinger/oppgavetekster/oving7/images/ObservableList_del2.png

116 KiB

ovinger/oppgavetekster/oving7/images/ObservableList_del3.png

118 KiB

ovinger/oppgavetekster/oving7/images/Train_del1.png

16 KiB

ovinger/oppgavetekster/oving7/images/Train_del2.png

52.2 KiB

ovinger/oppgavetekster/oving7/images/Train_del3.png

103 KiB

/.BSUTest.java._trace
/.CargoCarTest.java._trace
/.ForeldreSparTest.java._trace
/.SavingsAccountTest.java._trace
/.SimpleCalculatorTest.java._trace
/.TrainTest.java._trace
/.PassengerCarTest.java._trace
/.RPNCalculatorTest.java._trace
/.TrainCarTest.java._trace
/.CardDeckTest.java._trace
/.CardHandTest.java._trace
/.CreditAccountTest.java._trace
/.DebitAccountTest.java._trace
/.SavingsAccount2Test.java._trace
/.SpaceObjectTest.java._trace
package oving7;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class BSUTest {
private BSU bsu;
private static double epsilon = 0.001;
@BeforeEach
public void setUp() throws Exception {
bsu = new BSU(0.05, 25000.0);
}
@Test
@DisplayName("Sjekk at innskudd fungerer som det skal")
void testDeposit() {
bsu.deposit(10000.0);
assertEquals(10000.0, bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalArgumentException.class, () -> {
bsu.deposit(-100.0);
}, "Negativt innskudd burde gitt utløst IllegalArugment-unntak!");
assertThrows(IllegalStateException.class, () -> {
bsu.deposit(20000.0);
}, "Skal ikke kunne sette inn mer penger inn inskuddsgrensen");
bsu.endYearUpdate();
bsu.deposit(20000.0);
assertEquals(10000.0 * (1 + 0.05) + 20000.0, bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
}
@Test
@DisplayName("Sjekk at uttak fungerer som det skal")
void testWithdraw() {
bsu.deposit(20000.0);
bsu.withdraw(5000.0);
assertEquals(15000.0, bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalArgumentException.class, () -> {
bsu.withdraw(-10000.0);
}, "Negativt uttak burde gitt utløst IllegalArugment-unntak!");
assertEquals(15000.0, bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalStateException.class, () -> {
bsu.withdraw(20000);
}, "Skal ikke kunne ta ut mer penger enn er satt inn dette året");
assertEquals(15000.0, bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
bsu.endYearUpdate();
assertThrows(IllegalStateException.class, () -> {
bsu.withdraw(10000);
}, "Skal ikke kunne ta ut mer penger enn er satt inn dette året");
assertEquals(15000 * (1 + 0.05), bsu.getBalance(), epsilon, "Saldoen på kontoen ble feil");
}
@Test
@DisplayName("Sjekk at skattefradraget blir riktig")
public void testTaxDeduction() {
bsu.deposit(20000.0);
assertEquals(20000.0 * 0.20, bsu.getTaxDeduction(), epsilon, "Skattefradraget ble feil");
bsu.endYearUpdate();
bsu.deposit(10000.0);
assertEquals(10000.0 * 0.20, bsu.getTaxDeduction(), epsilon, "Skattefradraget ble feil");
bsu.endYearUpdate();
assertEquals(0.0, bsu.getTaxDeduction(), epsilon, "Skattefradraget ble feil");
}
}
\ No newline at end of file
package oving7;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CardDeckTest {
CardDeck deck;
Card s1;
Card s2;
Card h1;
Card h2;
Card d1;
Card d2;
Card c1;
Card c2;
List<Card> expected;
@BeforeEach
public void setUp() {
deck = new CardDeck(2);
s1 = new Card('S', 1);
s2 = new Card('S', 2);
h1 = new Card('H', 1);
h2 = new Card('H', 2);
d1 = new Card('D', 1);
d2 = new Card('D', 2);
c1 = new Card('C', 1);
c2 = new Card('C', 2);
expected = new LinkedList<Card>(Arrays.asList(s1, s2, h1, h2, d1, d2, c1, c2));
}
@Test
@DisplayName("Test maxCardCount")
public void testMaxCardCount() {
assertTrue(deck instanceof CardContainerImpl);
assertEquals(52, deck.getMaxCardCount());
}
@Test
@DisplayName("Test at cardDeckImpl implementerer cardContainer")
public void testCardContainer() {
testCards(deck, expected);
}
@Test
@DisplayName("Test at cardDeckImpl implementerer iterable")
public void testDeckIterator() {
testCards(deck.iterator(), expected.iterator());
}
private void testCards(CardContainer it, List<Card> expected) {
assertEquals(expected.size(), it.getCardCount());
for (int i = 0; i < expected.size(); i++) {
Card expectedCard = expected.get(i);
Card actualCard = it.getCard(i);
assertEquals(expectedCard.getSuit(), actualCard.getSuit(),
String.format("Kort nummer %d skulle vært %s men var %s ", i + 1, expectedCard, actualCard));
assertEquals(expectedCard.getFace(), actualCard.getFace(),
String.format("Kort nummer %d skulle vært %s men var %s ", i + 1, expectedCard, actualCard));
i++;
}
}
private void testCards(Iterator<Card> actual, Iterator<Card> expected) {
while (expected.hasNext()) {
assertTrue(actual.hasNext());
Card expectedCard = expected.next();
Card actualCard = actual.next();
assertEquals(expectedCard.getSuit(), actualCard.getSuit(),
String.format("Kortet skulle vært %s men var %s ", expectedCard, actualCard));
assertEquals(expectedCard.getFace(), actualCard.getFace(),
String.format("Kortet skulle vært %s men var %s", expectedCard, actualCard));
}
}
}
package oving7;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CardHandTest {
CardHand hand;
Card s1;
Card c2;
List<Card> expected;
@BeforeEach
public void setUp() {
hand = new CardHand(2);
s1 = new Card('S', 1);
c2 = new Card('C', 2);
expected = new LinkedList<Card>(Arrays.asList(s1, c2));
}
@Test
@DisplayName("Test cardCount")
public void testCardCount() {
assertTrue(hand instanceof CardContainerImpl);
assertEquals(0, hand.getCardCount(), "CardCount skulle vært 0 i begynnelsen");
hand.addCard(new Card('S', 1));
hand.addCard(new Card('S', 2));
assertEquals(2, hand.getCardCount(), "CardCount skulle vært 2 i begynnelsen");
}
@Test
@DisplayName("Test at cardDeckImpl implementerer cardContainer")
public void testCardContainer() {
hand.addCard(new Card('S', 1));
hand.addCard(new Card('C', 2));
testCards(hand, expected);
}
@Test
@DisplayName("Test at cardDeckImpl implementerer iterable")
public void testDeckIterator() {
hand.addCard(new Card('S', 1));
hand.addCard(new Card('C', 2));
testCards(hand.iterator(), expected.iterator());
}
private void testCards(CardContainer it, List<Card> expected) {
assertEquals(expected.size(), it.getCardCount());
for (int i = 0; i < expected.size(); i++) {
Card expectedCard = expected.get(i);
Card actualCard = it.getCard(i);
assertEquals(expectedCard.getSuit(), actualCard.getSuit(),
String.format("Kort nummer %d skulle vært %s men var %s ", i + 1, expectedCard, actualCard));
assertEquals(expectedCard.getFace(), actualCard.getFace(),
String.format("Kort nummer %d skulle vært %s men var %s ", i + 1, expectedCard, actualCard));
i++;
}
}
private void testCards(Iterator<Card> actual, Iterator<Card> expected) {
while (expected.hasNext()) {
assertTrue(actual.hasNext());
Card expectedCard = expected.next();
Card actualCard = actual.next();
assertEquals(expectedCard.getSuit(), actualCard.getSuit(),
String.format("Kortet skulle vært %s men var %s ", expectedCard, actualCard));
assertEquals(expectedCard.getFace(), actualCard.getFace(),
String.format("Kortet skulle vært %s men var %s", expectedCard, actualCard));
}
}
}
package oving7;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CargoCarTest {
private CargoCar cc;
@BeforeEach
public void setup() {
cc = new CargoCar(3000, 2000);
}
@Test
@DisplayName("Sjekke totalvekt")
public void testWeight() {
Assertions.assertEquals(5000, cc.getTotalWeight(), "Teste totalvekt etter initialisering");
cc.setCargoWeight(4000);
Assertions.assertEquals(7000, cc.getTotalWeight(), "Teste totalvekt etter endret cargo-vekt");
Assertions.assertEquals(4000, cc.getCargoWeight(), "Teste cargo-vekt etter endring i vekten");
}
}
\ No newline at end of file
package oving7;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class CreditAccountTest {
private CreditAccount sub;
private static double epsilon = 0.0005d;
@BeforeEach
public void setUp() {
sub = new CreditAccount(10000.0);
}
@Test
@DisplayName("Sjekk at innskudd fungerer som det skal")
void testDeposit() {
assertEquals(0.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
sub.deposit(10000.0);
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalArgumentException.class, () -> {
sub.deposit(-10000.0);
}, "Negativt innskudd burde gitt utløst IllegalArugment-unntak!");
assertEquals(10000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
}
@Test
@DisplayName("Sjekk at uttak fungerer som det skal")
void testWithdraw() {
sub.deposit(20000.0);
sub.withdraw(5000.0);
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalArgumentException.class, () -> {
sub.withdraw(-10000.0);
}, "Negativt uttak burde gitt utløst IllegalArugment-unntak!");
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
sub.withdraw(20000.0);
assertEquals(-5000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
assertThrows(IllegalStateException.class, () -> {
sub.withdraw(20000.0);
}, "Uttak på mer enn kredittgrense burde utløst IllegalState-unntak");
}
@Test
@DisplayName("Sjekk at kredittgrensen fungerer som den skal")
void testCreditLine() {
assertEquals(10000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
sub.setCreditLine(5000.0);
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
assertThrows(IllegalArgumentException.class, () -> {
sub.setCreditLine(-5000.0);
}, "Kan ikke ha negativ kredittgrense");
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
sub.withdraw(4000.0);
assertThrows(IllegalStateException.class, () -> {
sub.setCreditLine(3000.0);
}, "Kan ikke sette kredittgrense som vil gi ugyldig saldo");
assertEquals(-4000.0, sub.getBalance(), epsilon, "Saldoen var feil");
assertEquals(5000.0, sub.getCreditLine(), epsilon, "Kredittgrensen var feil");
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment