Add rest
|
@ -0,0 +1,3 @@
|
||||||
|
{
|
||||||
|
"java.configuration.updateBuildConfiguration": "automatic"
|
||||||
|
}
|
|
@ -3,11 +3,11 @@
|
||||||
Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmering våren 2021. Tabellen under inneholder linker til hver enkelt oppgavetekst og tema for øvingen. Linker vil bli oppdatert underveis.
|
Denne mappen inneholder øvingstekster for TDT4100 - Objektorientert programmering våren 2021. Tabellen under inneholder linker til hver enkelt oppgavetekst og tema for øvingen. Linker vil bli oppdatert underveis.
|
||||||
|
|
||||||
| Øving | Tema |
|
| Øving | Tema |
|
||||||
| ----------------- | ---------------------------------------- |
|
| --------------------------- | ---------------------------------------- |
|
||||||
| [Øving 1](oving1/README.md) | Tilstand og oppførsel |
|
| [Øving 1](oving1/README.md) | Tilstand og oppførsel |
|
||||||
| Øving 2 | Innkapsling og validering |
|
| [Øving 2](oving2/README.md) | Innkapsling og validering |
|
||||||
| Øving 3 | Klasser og testing |
|
| [Øving 3](oving3/README.md) | Klasser og testing |
|
||||||
| Øving 4 | Objektstrukturer |
|
| [Øving 4](oving4/README.md) | Objektstrukturer |
|
||||||
| Øving 5 | Grensesnitt |
|
| [Øving 5](oving5/README.md) | Grensesnitt |
|
||||||
| Øving 6 | Observatør-observert og delegering |
|
| [Øving 6](oving6/README.md) | Observatør-observert og delegering |
|
||||||
| Øving 7 | Arv og abstrakte klasser |
|
| [Øving 7](oving7/README.md) | Arv og abstrakte klasser |
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
# Fiks ved problemer med å pulle i Eclipse
|
||||||
|
|
||||||
|
Dersom du får problemer med å pulle øvinger i Eclipse, med feilmelding som vist i bildet under ("Checkout conflict with files: `<prosjektnavn>/.classpath`), kan du følge denne guiden for å løse problemet.
|
||||||
|
|
||||||
|
**NB!** Bildene i denne guiden går ut i fra at problemfilen ligger i `ovinger`-prosjektet, men det kan også være under et av de andre prosjektene.
|
||||||
|
Du kan se hvilke filer som er problematiske i feilmeldinga du får når du puller.
|
||||||
|
|
||||||
|
![Feilmelding ved pull](img/2.png)
|
||||||
|
|
||||||
|
| Beskrivelse | Bilde |
|
||||||
|
|------|-------|
|
||||||
|
| I Project-explorer i Eclipse, trykk på de tre prikkene i øvre høyre hjørne. I menyen som kommer opp velger du *Filters and Customization...* (I MacOS står det kun *Filters...*). | ![Meny](img/3.png) ![Filters and customization](img/4.png) |
|
||||||
|
| I vinduet som kommer opp, pass på at valget `.* resources` **IKKE** er valgt, og trykk ok. | ![Vis skjulte](img/5.png) |
|
||||||
|
| Åpne prosjektet du hadde konflikter i, dette er sannsynligvis ovinger. Du vil se at det har dukket opp en fil som heter `.classpath` under prosjektmappa. | ![Prosjekt med .classpath](img/6.png) |
|
||||||
|
| Høyreklikk på `.classpath`-fila, og velg *Replace With* -> *HEAD Revision*. Trykk *Discard Changes* i vinduet som kommer opp. | ![Replace with](img/7.png)) |
|
||||||
|
| Nå kan du prøve å pulle igjen (høyreklikk på prosjektet og velg *Team* -> *Pull*). Sannsynligvis vil prosjektet nå se ganske kaotisk ut, med veldig mange mapper. Det fikser du enkelt ved å høyreklikke på det, og velge *Maven* -> *Update Project*, velge alle prosjektene, og trykke *OK* | ![Mvn update](img/9.png) |
|
||||||
|
|
||||||
|
Etter denne prosessen skal alt fungere som før. Har du problemer, ta kontakt med undass.
|
After Width: | Height: | Size: 8.3 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 31 KiB |
After Width: | Height: | Size: 25 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 64 KiB |
After Width: | Height: | Size: 13 KiB |
After Width: | Height: | Size: 44 KiB |
|
@ -1,7 +1,7 @@
|
||||||
# Interface - CardContainer-oppgave
|
# Interface - CardContainer-oppgave
|
||||||
Denne oppgaven handler om å lage et felles grensesnitt for `CardDeck`- og `CardHand`-klassene, laget i oppgavene
|
Denne oppgaven handler om å lage et felles grensesnitt for `CardDeck`- og `CardHand`-klassene, laget i oppgavene
|
||||||
[Innkapsling - Card-oppgave](../oving3/Card.md) og
|
[Innkapsling - Card-oppgave](../oving3/Card.md) og
|
||||||
[Objektstrukturer - Card-oppgave del 2](../oving5/Card.md).
|
[Objektstrukturer - Card-oppgave del 2](../oving4/Card.md).
|
||||||
Her skal du lage og implementere et grensenitt kalt `CardContainer`, som spesifiserer metoder for lesing av samlinger av Card-objekter.
|
Her skal du lage og implementere et grensenitt kalt `CardContainer`, som spesifiserer metoder for lesing av samlinger av Card-objekter.
|
||||||
|
|
||||||
#### Del 1 - CardContainer interface
|
#### Del 1 - CardContainer interface
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
# 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: [inheritance/DebitAccountTest.java](../../src/test/java/inheritance/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: [inheritance/CreditAccountTest.java](../../src/test/java/inheritance/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: [inheritance/SavingsAccount2Test.java](../../src/test/java/inheritance/SavingsAccount2Test.java).
|
|
@ -0,0 +1,38 @@
|
||||||
|
# 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 løsningsforslaget som er lagt ut for disse under `lf/src/interfaces`.
|
||||||
|
|
||||||
|
### 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: [inheritance/CardDeckTest.java](../../src/test/java/inheritance/CardDeckTest.java) og [inheritance/CardHandTest.java](../../src/test/java/inheritance/CardHandTest.java).
|
|
@ -0,0 +1,140 @@
|
||||||
|
# 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/patterns.observable/` og tilhørende
|
||||||
|
tester ligger i `src/test/java/patterns.observable/`.
|
||||||
|
|
||||||
|
### 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: [patterns/observable/ObservableHighscoreListTest.java](../../src/test/java/patterns/observable/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: [patterns/observable/ObservableListTest.java](../../src/test/java/patterns/observable/ObservableListTest.java).
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
# Ø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/inheritance`.
|
||||||
|
|
||||||
|
I begge delene er antageligvis vanskelighetsgraden stigende. Alle er høyst eksamensrelevante og det anbefales følgelig å ta en titt på samtlige.
|
||||||
|
|
||||||
|
### 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.
|
|
@ -0,0 +1,117 @@
|
||||||
|
# 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 under
|
||||||
|
[Innkapsling](../oving2/Account.md) og [Tilstand og oppførsel](../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 inheritance;
|
||||||
|
|
||||||
|
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: [inheritance/SavingsAccountTest.java](../../src/test/java/inheritance/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: [inheritance/BSUTest.java](../../src/test/java/inheritance/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: [inheritance/ForeldreSparTest.java](../../src/test/java/inheritance/ForeldreSparTest.java).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
# 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: [inheritance/TrainCarTest.java](../../src/test/java/inheritance/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: [inheritance/PassengerCarTest.java](../../src/test/java/inheritance/PassengerCarTest.java) og [inheritance/CargoCarTest.java](../../src/test/java/inheritance/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: [inheritance/TrainTest.java](../../src/test/java/inheritance/TrainTest.java).
|
After Width: | Height: | Size: 81 KiB |
After Width: | Height: | Size: 116 KiB |
After Width: | Height: | Size: 118 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 52 KiB |
After Width: | Height: | Size: 103 KiB |
|
@ -0,0 +1,25 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public abstract class AbstractAccount {
|
||||||
|
|
||||||
|
protected double balance;
|
||||||
|
|
||||||
|
public void deposit(double amount) {
|
||||||
|
if (amount < 0)
|
||||||
|
throw new IllegalArgumentException("Can not deposit a negative amount of money.");
|
||||||
|
this.balance += amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void withdraw(double amount) {
|
||||||
|
if (amount < 0)
|
||||||
|
throw new IllegalArgumentException("Can not withdraw a negative amount of money.");
|
||||||
|
internalWithdraw(amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract void internalWithdraw(double amount);
|
||||||
|
|
||||||
|
public double getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public class CargoCar extends TrainCar {
|
||||||
|
|
||||||
|
private int cargoWeight;
|
||||||
|
|
||||||
|
public CargoCar(int deadWeight, int cargoWeight){
|
||||||
|
super(deadWeight);
|
||||||
|
this.setCargoWeight(cargoWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCargoWeight() {
|
||||||
|
return this.cargoWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCargoWeight(int cargoWeight) {
|
||||||
|
if (cargoWeight < 0)
|
||||||
|
throw new IllegalArgumentException("Cargo weight cannot be less than 0");
|
||||||
|
this.cargoWeight = cargoWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalWeight() {
|
||||||
|
return this.getDeadWeight() + this.getCargoWeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"(Cargo w:%d, cw:%d)",
|
||||||
|
this.getTotalWeight(),
|
||||||
|
this.getCargoWeight()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public class CreditAccount extends AbstractAccount {
|
||||||
|
|
||||||
|
private double creditLine;
|
||||||
|
|
||||||
|
public CreditAccount(double creditLine) {
|
||||||
|
this.setCreditLine(creditLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getCreditLine() {
|
||||||
|
return creditLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCreditLine(double creditLine) {
|
||||||
|
if (creditLine < 0)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
|
||||||
|
if (creditLine + super.getBalance() < 0)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
this.creditLine = creditLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalWithdraw(double amount) {
|
||||||
|
|
||||||
|
if (creditLine + super.getBalance() - amount < 0)
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
super.balance -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public class DebitAccount extends AbstractAccount {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalWithdraw(double amount) {
|
||||||
|
if (this.balance - amount < 0)
|
||||||
|
throw new IllegalStateException("The account does not contain enough money for the withdrawal.");
|
||||||
|
super.balance -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public class PassengerCar extends TrainCar {
|
||||||
|
|
||||||
|
private int passengerCount;
|
||||||
|
private static int passengerWeight = 80;
|
||||||
|
|
||||||
|
public PassengerCar(int deadWeight, int passengerCount) {
|
||||||
|
super(deadWeight);
|
||||||
|
this.setPassengerCount(passengerCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPassengerCount() {
|
||||||
|
return this.passengerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setPassengerCount(int passengerCount) {
|
||||||
|
if (passengerCount < 0)
|
||||||
|
throw new IllegalArgumentException("Passenger count cannot be less than 0");
|
||||||
|
this.passengerCount = passengerCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getTotalPassengerWeight() {
|
||||||
|
return this.getPassengerCount() * passengerWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTotalWeight() {
|
||||||
|
return this.getDeadWeight() + this.getTotalPassengerWeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"(Passengers w:%d, pc:%d)",
|
||||||
|
this.getTotalWeight(),
|
||||||
|
this.getPassengerCount()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
public class SavingsAccount2 extends AbstractAccount {
|
||||||
|
|
||||||
|
int withdrawals;
|
||||||
|
int withdrawalCount;
|
||||||
|
double fee;
|
||||||
|
|
||||||
|
public SavingsAccount2(int withdrawals, double fee) {
|
||||||
|
this.setWithdrawals(withdrawals);
|
||||||
|
this.setFee(fee);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWithdrawals(int withdrawals) {
|
||||||
|
if (withdrawals < 0)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
this.withdrawals = withdrawals;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFee(double fee) {
|
||||||
|
if (fee < 0)
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
this.fee = fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void internalWithdraw(double amount) {
|
||||||
|
if (withdrawalCount >= withdrawals)
|
||||||
|
amount += fee;
|
||||||
|
|
||||||
|
if (this.balance - amount < 0)
|
||||||
|
throw new IllegalStateException("The account does not contain enough money for the withdrawal.");
|
||||||
|
|
||||||
|
withdrawalCount++;
|
||||||
|
super.balance -= amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
public class Train {
|
||||||
|
private Collection<TrainCar> cars = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addTrainCar(TrainCar car) {
|
||||||
|
this.cars.add(car);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean contains(TrainCar car) {
|
||||||
|
return this.cars.contains(car);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalWeight() {
|
||||||
|
return
|
||||||
|
this.cars
|
||||||
|
.stream()
|
||||||
|
.map(car -> car.getTotalWeight())
|
||||||
|
.reduce(0, (a, b) -> a+b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getPassengerCount() {
|
||||||
|
return
|
||||||
|
this.cars
|
||||||
|
.stream()
|
||||||
|
.filter(car -> car instanceof PassengerCar)
|
||||||
|
.map(car -> (PassengerCar) car)
|
||||||
|
.map(pcar -> pcar.getPassengerCount())
|
||||||
|
.reduce(0, (a, b) -> a+b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCargoWeight() {
|
||||||
|
return
|
||||||
|
this.cars
|
||||||
|
.stream()
|
||||||
|
.filter(car -> car instanceof CargoCar)
|
||||||
|
.map(car -> (CargoCar) car)
|
||||||
|
.map(ccar -> ccar.getCargoWeight())
|
||||||
|
.reduce(0, (a, b) -> a+b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return
|
||||||
|
"\uD83D\uDE82 - "
|
||||||
|
+ this.cars
|
||||||
|
.stream()
|
||||||
|
.map(car -> car.toString())
|
||||||
|
.collect(Collectors.joining(" - "));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
|
||||||
|
public class TrainCar {
|
||||||
|
private int deadWeight;
|
||||||
|
|
||||||
|
public TrainCar(int deadWeight) {
|
||||||
|
this.setDeadWeight(deadWeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTotalWeight() {
|
||||||
|
return deadWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeadWeight(int deadWeight) {
|
||||||
|
if (deadWeight < 0)
|
||||||
|
throw new IllegalArgumentException("Deadweight cannot be less than 0");
|
||||||
|
this.deadWeight = deadWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getDeadWeight() {
|
||||||
|
return this.deadWeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return String.format(
|
||||||
|
"(Car w:%d)",
|
||||||
|
this.getTotalWeight()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
class HighscoreList {
|
||||||
|
|
||||||
|
private int maxSize;
|
||||||
|
private List<Integer> results;
|
||||||
|
private List<HighscoreListListener> listeners;
|
||||||
|
|
||||||
|
public HighscoreList(int maxSize) {
|
||||||
|
this.maxSize = maxSize;
|
||||||
|
this.results = new ArrayList<>();
|
||||||
|
this.listeners = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return results.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getElement(int n) {
|
||||||
|
return results.get(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addResult(int result) {
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
if (results.isEmpty())
|
||||||
|
results.add(result);
|
||||||
|
|
||||||
|
else {
|
||||||
|
while (i + 1 < results.size() && results.get(i) <= result)
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if (i + 1 == results.size())
|
||||||
|
results.add(result);
|
||||||
|
else
|
||||||
|
results.add(i, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (results.size() > maxSize)
|
||||||
|
results.remove(maxSize);
|
||||||
|
|
||||||
|
System.out.println(results);
|
||||||
|
System.out.println(i);
|
||||||
|
|
||||||
|
boolean elementWasDeleted = i + 1 == this.maxSize;
|
||||||
|
|
||||||
|
for (var listener : listeners)
|
||||||
|
listener.listChanged(this, elementWasDeleted ? -1 : i);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addHighscoreListListener(HighscoreListListener listener) {
|
||||||
|
this.listeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeHighscoreListListener(HighscoreListListener listener) {
|
||||||
|
this.listeners.remove(listener);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
interface HighscoreListListener {
|
||||||
|
void listChanged(HighscoreList list, int n);
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
public class HighscoreListProgram implements HighscoreListListener {
|
||||||
|
|
||||||
|
private HighscoreList list;
|
||||||
|
|
||||||
|
/** oppretter en ny HighscoreList og registrerer seg selv (altså HighscoreListProgram-instansen) som lytter */
|
||||||
|
public void init() {
|
||||||
|
this.list = new HighscoreList(4);
|
||||||
|
|
||||||
|
this.list.addHighscoreListListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** leser inn tall (resultater) fra konsollet og legger dem til i listen */
|
||||||
|
public void run() {
|
||||||
|
try(Scanner scanner = new Scanner(System.in)){
|
||||||
|
var i = scanner.nextInt();
|
||||||
|
// this.list.addResult(i);
|
||||||
|
System.out.println(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** observerer endringer i HighscoreList-instansen og skriver ut posisjonsargumentet, samt selve listen, til konsollen. */
|
||||||
|
public void listChanged(HighscoreList list, int i) {
|
||||||
|
System.out.println(list.toString() + " " + i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
HighscoreListProgram prog = new HighscoreListProgram();
|
||||||
|
prog.init();
|
||||||
|
while (true) {
|
||||||
|
prog.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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(), "Totalvekt ble feil etter initialisering");
|
||||||
|
cc.setCargoWeight(4000);
|
||||||
|
Assertions.assertEquals(7000, cc.getTotalWeight(), "Totalvekt ble feil etter endret cargo-vekt");
|
||||||
|
Assertions.assertEquals(4000, cc.getCargoWeight(), "Cargo-vekt ble feil etter endring i cargo-vekt");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,65 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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 DebitAccountTest {
|
||||||
|
private DebitAccount sub;
|
||||||
|
private static double epsilon = 0.0005d;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
sub = new DebitAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
@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");
|
||||||
|
assertThrows(IllegalStateException.class, () -> {
|
||||||
|
sub.withdraw(20000.0);
|
||||||
|
}, "Uttak på mer enn saldo burde utløst IllegalState-unntak");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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 PassengerCarTest {
|
||||||
|
|
||||||
|
private PassengerCar pc;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
pc = new PassengerCar(3000, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekke totalvekt med passasjerer")
|
||||||
|
public void testWeight() {
|
||||||
|
Assertions.assertEquals(3000 + (200 * 80), pc.getTotalWeight(), "Totalvekt ble feil etter initialisering");
|
||||||
|
pc.setPassengerCount(100);
|
||||||
|
Assertions.assertEquals(3000 + (100 * 80), pc.getTotalWeight(),
|
||||||
|
"Totalvekt ble feil etter endret passasjer-antall");
|
||||||
|
Assertions.assertEquals(100, pc.getPassengerCount(),
|
||||||
|
"Antall passasjerer ble feil etter kall av setPassengerCount");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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 SavingsAccount2Test {
|
||||||
|
private SavingsAccount2 sub;
|
||||||
|
private static double epsilon = 0.0005d;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setUp() {
|
||||||
|
sub = new SavingsAccount2(1, 50.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 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 utløst IllegalArugment-unntak!");
|
||||||
|
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||||
|
assertThrows(IllegalStateException.class, () -> {
|
||||||
|
sub.withdraw(20000.0);
|
||||||
|
}, "Uttak på mer enn saldo burde utløst IllegalState-unntak");
|
||||||
|
assertEquals(15000.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil");
|
||||||
|
sub.withdraw(10000.0);
|
||||||
|
assertEquals(4950.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil etter at gebyret var trukket fra");
|
||||||
|
assertThrows(IllegalStateException.class, () -> {
|
||||||
|
sub.withdraw(4930.0);
|
||||||
|
}, "Uttak på mer enn saldo + gebyr burde utløst IllegalState-unntak");
|
||||||
|
assertEquals(4950.0, sub.getBalance(), epsilon, "Saldoen på kontoen ble feil etter at gebyret var trukket fra");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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 TrainCarTest {
|
||||||
|
|
||||||
|
private TrainCar tc;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
tc = new TrainCar(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekk at dødvekt er det samme som totalvekt")
|
||||||
|
public void testDeadWeight() {
|
||||||
|
Assertions.assertEquals(3000, tc.getTotalWeight(), "Totalvekt skulle vært samme som dødvekt");
|
||||||
|
tc.setDeadWeight(5000);
|
||||||
|
Assertions.assertEquals(5000, tc.getTotalWeight(), "Totalvekt skulle vært samme som dødvekt");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,73 @@
|
||||||
|
package inheritance;
|
||||||
|
|
||||||
|
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 TrainTest {
|
||||||
|
|
||||||
|
private Train train;
|
||||||
|
private PassengerCar pc1, pc2;
|
||||||
|
private CargoCar cc1, cc2;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
train = new Train();
|
||||||
|
pc1 = new PassengerCar(2000, 200);
|
||||||
|
pc2 = new PassengerCar(1500, 100);
|
||||||
|
cc1 = new CargoCar(3000, 5000);
|
||||||
|
cc2 = new CargoCar(2500, 7000);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekk at toget inneholder vogner etter at de er lagt til")
|
||||||
|
public void testAddCarToTrain() {
|
||||||
|
train.addTrainCar(pc1);
|
||||||
|
train.addTrainCar(pc2);
|
||||||
|
train.addTrainCar(cc1);
|
||||||
|
Assertions.assertTrue(train.contains(pc1), "Toget skulle inneholdt passasjervogn 1 etter at det er lagt til");
|
||||||
|
Assertions.assertTrue(train.contains(pc2), "Toget skulle inneholdt passasjervogn 2 etter at det er lagt til");
|
||||||
|
Assertions.assertTrue(train.contains(cc1), "Toget skulle inneholdt lastvogn 1 etter at det er lagt til");
|
||||||
|
Assertions.assertFalse(train.contains(cc2), "Toget skulle inneholdt lastvogn 2 etter at det er lagt til");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekke totalvekt på toget etter å ha lagt til vogner")
|
||||||
|
public void testTotalTrainWeight() {
|
||||||
|
train.addTrainCar(pc1);
|
||||||
|
train.addTrainCar(cc1);
|
||||||
|
|
||||||
|
Assertions.assertEquals(8000 + (2000 + (200 * 80)), train.getTotalWeight(),
|
||||||
|
"Togets totalvekt ble feil etter å ha lagt til to vogner");
|
||||||
|
|
||||||
|
train.addTrainCar(pc2);
|
||||||
|
|
||||||
|
Assertions.assertEquals(8000 + (2000 + (200 * 80)) + (1500 + (100 * 80)), train.getTotalWeight(),
|
||||||
|
"Togets totalvekt ble feil etter å ha lagt til enda en passasjervogn");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekk total passajerantall etter å ha lagt til to passasjervogner")
|
||||||
|
public void testPassengerCount() {
|
||||||
|
train.addTrainCar(pc1);
|
||||||
|
train.addTrainCar(pc2);
|
||||||
|
Assertions.assertEquals(300, train.getPassengerCount(),
|
||||||
|
"Passasjerantall ble feil etter å ha lagt til to passasjervogner");
|
||||||
|
train.addTrainCar(cc1);
|
||||||
|
Assertions.assertEquals(300, train.getPassengerCount(),
|
||||||
|
"Passasjerantall ble feil etter å ha lagt til en lastvogn");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekk lastvekt på toget etter å ha lagt til to lastvogner")
|
||||||
|
public void testCargoWeight() {
|
||||||
|
train.addTrainCar(cc1);
|
||||||
|
train.addTrainCar(cc2);
|
||||||
|
Assertions.assertEquals(12000, train.getCargoWeight(), "Lastvekt ble feil etter å ha lagt til to lastvogner");
|
||||||
|
|
||||||
|
train.addTrainCar(pc1);
|
||||||
|
Assertions.assertEquals(12000, train.getCargoWeight(),
|
||||||
|
"Lastvekt ble feil etter å ha lagt til en passasjervogn");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
/.ObservableHighscoreListTest.java._trace
|
||||||
|
/.HighscoreListTest.java._trace
|
||||||
|
/.ObservableListTest.java._trace
|
||||||
|
/.StockTest.java._trace
|
||||||
|
/.StockIndexTest.java._trace
|
||||||
|
/.StopWatchManagerTest.java._trace
|
||||||
|
/.StopWatchTest.java._trace
|
||||||
|
/.SmartStockTest.java._trace
|
|
@ -0,0 +1,140 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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 HighscoreListTest{
|
||||||
|
|
||||||
|
private HighscoreList highscoreList;
|
||||||
|
private int pos1, pos2;
|
||||||
|
|
||||||
|
private void checkHighscoreList(String contextMessage, HighscoreList list, List<Integer> elements) {
|
||||||
|
Assertions.assertEquals(elements.size(), list.size(), contextMessage + " -> Teste lengden på highscore-listen");
|
||||||
|
int i = 0;
|
||||||
|
for (int element:elements) {
|
||||||
|
Assertions.assertEquals(element, list.getElement(i), contextMessage + " -> Teste at element på plass " + i + " stemmer");
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addResultWithListener(int pos, int element) {
|
||||||
|
pos1 = pos;
|
||||||
|
highscoreList.addResult(element);
|
||||||
|
|
||||||
|
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||||
|
Assertions.assertEquals(pos1, pos2, "La til " + element + " på posisjon " + pos + " -> Teste posisjonen mottatt av lytter");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
highscoreList = new HighscoreList(3);
|
||||||
|
pos1 = -1;
|
||||||
|
pos2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste konstruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals(0, highscoreList.size(), "Teste initialisering av highscore-listen");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til resultater (enkel)")
|
||||||
|
public void testAddElementSimple() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
checkHighscoreList("La til 5 i tom liste",highscoreList, Arrays.asList(5));
|
||||||
|
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
checkHighscoreList("La til 6 i listen [5]",highscoreList, Arrays.asList(5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til resultater - listen blir for lang")
|
||||||
|
public void testAddElementMoreThanMax() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(3);
|
||||||
|
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
|
||||||
|
highscoreList.addResult(7);
|
||||||
|
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til to like elementer")
|
||||||
|
public void testAddElementDuplicate() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste lyttere (enkel)")
|
||||||
|
public void testListListenersSimple() {
|
||||||
|
// Mocke en lytter
|
||||||
|
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addHighscoreListListener(listener);
|
||||||
|
|
||||||
|
addResultWithListener(0, 5);
|
||||||
|
checkHighscoreList("La til 5 i listen []", highscoreList, Arrays.asList(5));
|
||||||
|
|
||||||
|
addResultWithListener(1, 6);
|
||||||
|
checkHighscoreList("La til 6 i listen [5]",highscoreList, Arrays.asList(5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(0, 2);
|
||||||
|
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Med lytter - listen blir for lang")
|
||||||
|
public void testListListenerMoreThanMax() {
|
||||||
|
// Mocke en lytter
|
||||||
|
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addHighscoreListListener(listener);
|
||||||
|
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen",highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(1, 3);
|
||||||
|
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
|
||||||
|
// Nullstille pos2 siden neste element havner utenfor listen og blir dermed ikke oppdatert av seg selv og sendt til lytter
|
||||||
|
pos2 = -1;
|
||||||
|
addResultWithListener(-1, 7);
|
||||||
|
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Med lytter - to like elementer")
|
||||||
|
public void testListListenerDuplicate() {
|
||||||
|
// Mocke en lytter
|
||||||
|
HighscoreListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addHighscoreListListener(listener);
|
||||||
|
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen",highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(1, 2);
|
||||||
|
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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 ObservableHighscoreListTest {
|
||||||
|
|
||||||
|
private ObservableHighscoreList highscoreList;
|
||||||
|
private int pos1, pos2;
|
||||||
|
|
||||||
|
private void checkHighscoreList(String contextMessage, ObservableHighscoreList list, List<Integer> elements) {
|
||||||
|
Assertions.assertEquals(elements.size(), list.size(),
|
||||||
|
contextMessage + " -> Lengden på highscore-listen ble feil");
|
||||||
|
int i = 0;
|
||||||
|
for (int element : elements) {
|
||||||
|
Assertions.assertEquals(element, list.getElement(i),
|
||||||
|
contextMessage + String.format(" -> Elementet på plass %d ble feil", i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addResultWithListener(int pos, int element) {
|
||||||
|
pos1 = pos;
|
||||||
|
highscoreList.addResult(element);
|
||||||
|
|
||||||
|
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||||
|
Assertions.assertEquals(pos1, pos2, "La til " + element + " på posisjon " + pos
|
||||||
|
+ "Posisjonen som ble endret var ikke samme som ble sendt til lytteren");
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
highscoreList = new ObservableHighscoreList(3);
|
||||||
|
pos1 = -1;
|
||||||
|
pos2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste konstruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals(0, highscoreList.size(), "Highscorelist ble ikke initialisert til en tom liste");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til resultater (enkel)")
|
||||||
|
public void testAddElementSimple() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
checkHighscoreList("La til 5 i tom liste", highscoreList, Arrays.asList(5));
|
||||||
|
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
checkHighscoreList("La til 6 i listen [5]", highscoreList, Arrays.asList(5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til resultater - listen blir for lang")
|
||||||
|
public void testAddElementMoreThanMax() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(3);
|
||||||
|
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
|
||||||
|
highscoreList.addResult(7);
|
||||||
|
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til to like elementer")
|
||||||
|
public void testAddElementDuplicate() {
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste lyttere (enkel)")
|
||||||
|
public void testListListenersSimple() {
|
||||||
|
// Mocke en lytter
|
||||||
|
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addObservableListListener(listener);
|
||||||
|
|
||||||
|
addResultWithListener(0, 5);
|
||||||
|
checkHighscoreList("La til 5 i listen []", highscoreList, Arrays.asList(5));
|
||||||
|
|
||||||
|
addResultWithListener(1, 6);
|
||||||
|
checkHighscoreList("La til 6 i listen [5]", highscoreList, Arrays.asList(5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(0, 2);
|
||||||
|
checkHighscoreList("La til 2 i listen [5, 6]", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Med lytter - listen blir for lang")
|
||||||
|
public void testListListenerMoreThanMax() {
|
||||||
|
// Mocke en lytter
|
||||||
|
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addObservableListListener(listener);
|
||||||
|
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(1, 3);
|
||||||
|
checkHighscoreList("La til 3 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
|
||||||
|
// Nullstille pos2 siden neste element havner utenfor listen og blir dermed ikke
|
||||||
|
// oppdatert av seg selv og sendt til lytter
|
||||||
|
pos2 = -1;
|
||||||
|
addResultWithListener(-1, 7);
|
||||||
|
checkHighscoreList("La til 7 i listen [2, 3, 5]", highscoreList, Arrays.asList(2, 3, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Med lytter - to like elementer")
|
||||||
|
public void testListListenerDuplicate() {
|
||||||
|
// Mocke en lytter
|
||||||
|
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
highscoreList.addObservableListListener(listener);
|
||||||
|
|
||||||
|
highscoreList.addResult(5);
|
||||||
|
highscoreList.addResult(6);
|
||||||
|
highscoreList.addResult(2);
|
||||||
|
checkHighscoreList("La til 5, 6 og 2 i listen", highscoreList, Arrays.asList(2, 5, 6));
|
||||||
|
|
||||||
|
addResultWithListener(1, 2);
|
||||||
|
checkHighscoreList("La til 2 i listen [2, 5, 6]", highscoreList, Arrays.asList(2, 2, 5));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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 ObservableListTest {
|
||||||
|
|
||||||
|
private ObservableList observableList;
|
||||||
|
private int pos1, pos2;
|
||||||
|
|
||||||
|
private void checkObservableList(ObservableList list, List<Integer> elements, String contextMessage) {
|
||||||
|
Assertions.assertEquals(elements.size(), list.size(),
|
||||||
|
contextMessage + " -> Lengden på ObservableList ble feil");
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (int element : elements) {
|
||||||
|
Assertions.assertEquals(element, list.getElement(i),
|
||||||
|
contextMessage + String.format(" -> Element på plass %d var feil", i));
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addElementWithListener(int pos, int element) {
|
||||||
|
pos1 = pos;
|
||||||
|
observableList.addElement(pos, element);
|
||||||
|
|
||||||
|
// Sjekke at posisjonen som ble endret er den samme som ble sendt til lytteren
|
||||||
|
Assertions.assertEquals(pos1, pos2,
|
||||||
|
"La til " + element + " på posisjon " + pos + "posisjonen mottat av lytter ble feil, den var " + pos2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
observableList = new ObservableList() {
|
||||||
|
@Override
|
||||||
|
public boolean acceptsElement(final Object element) {
|
||||||
|
return (element instanceof Integer);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
pos1 = -1;
|
||||||
|
pos2 = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Test konstruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals(0, observableList.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Sjekk at listen aksepterer riktige elementer")
|
||||||
|
public void testAcceptsElement() {
|
||||||
|
Assertions.assertTrue(observableList.acceptsElement(5), "Listen skulle akseptert integers");
|
||||||
|
Assertions.assertFalse(observableList.acceptsElement("5"), "Listen skulle ikke akseptert strenger");
|
||||||
|
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
observableList.addElement("5");
|
||||||
|
}, "Listen skulle utløst et IllegalArgument-unntak når man prøver å legge til en streng");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste å legge til elementer")
|
||||||
|
public void testAddElement() {
|
||||||
|
observableList.addElement(5);
|
||||||
|
checkObservableList(observableList, Arrays.asList(5), "La til 5 i tom liste");
|
||||||
|
|
||||||
|
observableList.addElement(6);
|
||||||
|
checkObservableList(observableList, Arrays.asList(5, 6), "La til 6 i listen [5]");
|
||||||
|
|
||||||
|
observableList.addElement(0, 2);
|
||||||
|
checkObservableList(observableList, Arrays.asList(2, 5, 6), "La til 2 på posisjon 0 i listen [5, 6]");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste lytter")
|
||||||
|
public void testListListener() {
|
||||||
|
ObservableListListener listener = (list, pos) -> pos2 = pos;
|
||||||
|
observableList.addObservableListListener(listener);
|
||||||
|
|
||||||
|
addElementWithListener(0, 5);
|
||||||
|
checkObservableList(observableList, Arrays.asList(5), "La til 5 i listen []");
|
||||||
|
|
||||||
|
addElementWithListener(1, 6);
|
||||||
|
checkObservableList(observableList, Arrays.asList(5, 6), "La til 6 i listen [5]");
|
||||||
|
|
||||||
|
addElementWithListener(0, 2);
|
||||||
|
checkObservableList(observableList, Arrays.asList(2, 5, 6), "La til 2 i listen [5, 6]");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
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 SmartStockTest{
|
||||||
|
|
||||||
|
private SmartStock stock;
|
||||||
|
|
||||||
|
private double oldPrice, newPrice;
|
||||||
|
|
||||||
|
// Brukes for å sjekke at lyttere funker
|
||||||
|
private double oldPriceListener, newPriceListener;
|
||||||
|
|
||||||
|
private void setPriceForListener(double oldPrice, double newPrice) {
|
||||||
|
oldPriceListener = oldPrice;
|
||||||
|
newPriceListener = newPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPriceCheckListener(String contextMessage, double newPrice, double expectedOldPrice, double expectedNewPrice) {
|
||||||
|
// Oppdatere prisen
|
||||||
|
this.oldPrice = this.newPrice;
|
||||||
|
this.newPrice = newPrice;
|
||||||
|
stock.setPrice(newPrice);
|
||||||
|
|
||||||
|
// Sjekke at lytter har mottatt endring
|
||||||
|
Assertions.assertEquals(expectedOldPrice, this.oldPriceListener, contextMessage + " -> Teste gammel pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||||
|
Assertions.assertEquals(expectedNewPrice, this.newPriceListener, contextMessage + " -> Teste ny pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
stock = new SmartStock("APPL", 110.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste kontruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals("APPL", stock.getTicker(), "Teste ticker");
|
||||||
|
Assertions.assertEquals(110.0, stock.getPrice(), "Teste aksjeprisen");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Negativ aksjepris gir feilmelding")
|
||||||
|
public void testSetNegativePrice() {
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
stock.setPrice(-20.0);
|
||||||
|
}, "Teste å sette negativ aksjepris");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Aksjepris lik null gir feilmelding")
|
||||||
|
public void testSetZeroPrice() {
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
stock.setPrice(0);
|
||||||
|
}, "Teste å sette aksjepris lik null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til lytter")
|
||||||
|
public void testStockListener() {
|
||||||
|
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||||
|
stock.addStockListener(listener);
|
||||||
|
|
||||||
|
setPriceCheckListener("Lytter på alt", 118.0, 110.0, 118.0);
|
||||||
|
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||||
|
|
||||||
|
setPriceCheckListener("Lytter på alt", 121.0, 118.0, 121.0);
|
||||||
|
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris 2 ganger");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste lytter på prisintervall")
|
||||||
|
public void testIntervalListener() {
|
||||||
|
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||||
|
stock.addStockListener(listener, 110.0, 120.0);
|
||||||
|
|
||||||
|
// Pris innenfor intervallet gir ingen beskjed til lytter
|
||||||
|
setPriceCheckListener("Lytter på prisintervall", 118.0, 0.0, 0.0);
|
||||||
|
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||||
|
|
||||||
|
// Pris utenfor intervallet gir beskjed til lytter
|
||||||
|
setPriceCheckListener("Lytter på prisintervall",121.0, 118.0, 121.0);
|
||||||
|
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris for andre gang");
|
||||||
|
|
||||||
|
// Pris innenfor intervallet gir ingen beskjed til lytter (forventende verdier forblir det de var)
|
||||||
|
setPriceCheckListener("Lytter på prisintervall",115.0, 118.0, 121.0);
|
||||||
|
Assertions.assertEquals(115.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris for tredje gang");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste lytter på differanse")
|
||||||
|
public void testDifferenceListener() {
|
||||||
|
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||||
|
stock.addStockListener(listener, 10.0);
|
||||||
|
|
||||||
|
// Pris med differanse mindre enn 10 varsler ikke lytter
|
||||||
|
setPriceCheckListener("Lytter på differanse",118.0, 0.0, 0.0);
|
||||||
|
Assertions.assertEquals(118.0, stock.getPrice());
|
||||||
|
|
||||||
|
// Pris med differanse større enn 10 varsler lytter
|
||||||
|
setPriceCheckListener("Lytter på differanse",121.0, 110.0, 121.0);
|
||||||
|
Assertions.assertEquals(121.0, stock.getPrice());
|
||||||
|
|
||||||
|
// Pris med differanse mindre enn 10 varsler ikke lytter (forventende verdier forblir det de var)
|
||||||
|
setPriceCheckListener("Lytter på differanse", 115.0, 110.0, 121.0);
|
||||||
|
Assertions.assertEquals(115.0, stock.getPrice());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
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 StockIndexTest{
|
||||||
|
|
||||||
|
private static final double facebookPrice = 67.80d;
|
||||||
|
private static final double applePrice = 534.98;
|
||||||
|
private static final double epsilon = 0.000001d;
|
||||||
|
|
||||||
|
private Stock facebook, apple;
|
||||||
|
private StockIndex index0, index1, indexN;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
facebook = new Stock("FB", facebookPrice);
|
||||||
|
apple = new Stock("AAPL", applePrice);
|
||||||
|
|
||||||
|
index0 = new StockIndex("OSEBX");
|
||||||
|
index1 = new StockIndex("OSEBX", facebook);
|
||||||
|
indexN = new StockIndex("OSEBX", facebook, apple);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste konstruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer ");
|
||||||
|
Assertions.assertEquals(facebookPrice, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje");
|
||||||
|
Assertions.assertEquals(facebookPrice + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til aksje")
|
||||||
|
public void testAddStock() {
|
||||||
|
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer");
|
||||||
|
index0.addStock(facebook);
|
||||||
|
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til 1 aksje");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til samme aksje to ganger")
|
||||||
|
public void testAddDuplicateStocks() {
|
||||||
|
Assertions.assertEquals(0.0, index0.getIndex(), epsilon, "Teste verdien til indeks med 0 aksjer");
|
||||||
|
|
||||||
|
index0.addStock(facebook);
|
||||||
|
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til 1 aksje");
|
||||||
|
|
||||||
|
index0.addStock(facebook);
|
||||||
|
Assertions.assertEquals(facebookPrice, index0.getIndex(), epsilon, "Teste verdien til indeks etter å ha lagt til aksje som allerede er med i indeks");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Fjerne aksje")
|
||||||
|
public void testRemoveStock() {
|
||||||
|
Assertions.assertEquals(facebookPrice + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer");
|
||||||
|
|
||||||
|
indexN.removeStock(apple);
|
||||||
|
Assertions.assertEquals(facebookPrice, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet 1 aksje");
|
||||||
|
|
||||||
|
indexN.removeStock(apple);
|
||||||
|
Assertions.assertEquals(facebookPrice, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet 1 aksje som ikke var med i indeks");
|
||||||
|
|
||||||
|
indexN.removeStock(facebook);
|
||||||
|
Assertions.assertEquals(0.0, indexN.getIndex(), epsilon, "Teste verdien til indeks etter å ha fjernet eneste aksje i indeks");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Endre aksjepris")
|
||||||
|
public void testChangePrice() {
|
||||||
|
double facebookPrice2 = 67.0;
|
||||||
|
double facebookPrice3 = 69.0;
|
||||||
|
|
||||||
|
facebook.setPrice(facebookPrice2);
|
||||||
|
Assertions.assertEquals(facebookPrice2, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje etter å ha endret prisen på aksje");
|
||||||
|
Assertions.assertEquals(facebookPrice2 + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer etter å ha endret prisen til 1 av aksjene");
|
||||||
|
|
||||||
|
facebook.setPrice(facebookPrice3);
|
||||||
|
Assertions.assertEquals(facebookPrice3, index1.getIndex(), epsilon, "Teste verdien til indeks med 1 aksje etter å ha endret prisen på aksje for andre gang");
|
||||||
|
Assertions.assertEquals(facebookPrice3 + applePrice, indexN.getIndex(), epsilon, "Teste verdien til indeks med 2 aksjer etter å ha endret prisen til 1 av aksjene for andre gang");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
package patterns.observable;
|
||||||
|
|
||||||
|
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 StockTest{
|
||||||
|
|
||||||
|
private Stock stock;
|
||||||
|
private double oldPrice, newPrice;
|
||||||
|
|
||||||
|
// Brukes for å sjekke at lyttere funker
|
||||||
|
private double oldPriceListener, newPriceListener;
|
||||||
|
|
||||||
|
private void setPriceForListener(double oldPrice, double newPrice) {
|
||||||
|
oldPriceListener = oldPrice;
|
||||||
|
newPriceListener = newPrice;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setPriceCheckListener(double newPrice, double expectedOldPrice, double expectedNewPrice) {
|
||||||
|
// Oppdatere prisen
|
||||||
|
this.oldPrice = this.newPrice;
|
||||||
|
this.newPrice = newPrice;
|
||||||
|
stock.setPrice(newPrice);
|
||||||
|
|
||||||
|
// Sjekke at lytter har mottatt endring
|
||||||
|
Assertions.assertEquals(expectedOldPrice, this.oldPriceListener, "Teste gammel pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||||
|
Assertions.assertEquals(expectedNewPrice, this.newPriceListener, "Teste ny pris for lytter etter å ha oppdatert pris fra " + oldPrice + " til " + newPrice);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setup() {
|
||||||
|
stock = new Stock("APPL", 110.0);
|
||||||
|
oldPrice = 0.0; newPrice = 110.0;
|
||||||
|
oldPriceListener = 0.0; newPriceListener = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Teste kontruktør")
|
||||||
|
public void testConstructor() {
|
||||||
|
Assertions.assertEquals("APPL", stock.getTicker(), "Teste ticker");
|
||||||
|
Assertions.assertEquals(110.0, stock.getPrice(), "Teste aksjeprisen");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Negativ aksjepris gir feilmelding")
|
||||||
|
public void testSetNegativePrice() {
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
stock.setPrice(-20.0);
|
||||||
|
}, "Teste å sette negativ aksjepris");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Aksjepris lik null gir feilmelding")
|
||||||
|
public void testSetZeroPrice() {
|
||||||
|
Assertions.assertThrows(IllegalArgumentException.class, () -> {
|
||||||
|
stock.setPrice(0);
|
||||||
|
}, "Teste å sette aksjepris lik null");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("Legge til lytter")
|
||||||
|
public void testStockListener() {
|
||||||
|
StockListener listener = (Stock stock, double oldPrice, double newPrice) -> setPriceForListener(oldPrice, newPrice);
|
||||||
|
stock.addStockListener(listener);
|
||||||
|
|
||||||
|
setPriceCheckListener(118.0, 110.0, 118.0);
|
||||||
|
Assertions.assertEquals(118.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris");
|
||||||
|
|
||||||
|
setPriceCheckListener(121.0, 118.0, 121.0);
|
||||||
|
Assertions.assertEquals(121.0, stock.getPrice(), "Teste aksjepris etter å ha oppdatert pris 2 ganger");
|
||||||
|
}
|
||||||
|
}
|