7.8 KiB
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 avaddResult
, slik at resultater som er for dårlige kastes.size()
- returnerer antall elementer i lista, som altså aldri skal overstige maks-antalletint getElement(int)
- returnerer resultatet i posisjonen angitt av argumentetvoid 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 lytterremoveObservableListListener(ObservableListListener)
- fjerner en tidligere registrert lytter
Klassediagram for HighscoreList
, ListListener
og ObservableList
:
Testkode for denne oppgaven finner du her: 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 nyObservableHighscoreList
og registrerer seg selv (altsåObservableHighscoreListProgram
-instansen) som lyttervoid run()
- leser inn tall (resultater) fra konsollet og legger dem til i listenvoid listChanged(ObservableList, int)
- observerer endringer iObservableHighscoreList
-instansen og skriver ut posisjonsargumentet, samt selve listen, til konsollet
Klassediagrammet viser hvordan klassene henger sammen, og vårt forslag til metoder:
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 listaObject getElement(int)
- returnerer elementet i posisjonen angitt av argumentetabstract boolean acceptsElement(Object)
- returnerer hvorvidt subklassen aksepterer at objektet legges inn i lista (f.eks. akseptererHighscoreList
kunInteger
-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å skalIllegalArgumentException
utløses. Dersom posisjonen er ulovlig så skalIndexOutOfBoundsException
utløses.void addElement(Object)
- legger til et element bakerst i lista, men bare dersom det aksepteres som element. Dersom elementet ikke aksepteres, så skalIllegalArgumentException
utløses.void removeElement(int)
- fjerner elementet på posisjonen angitt av argumentet. Dersom posisjonen er ulovlig så skalIndexOutOfBoundsException
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.
Testkode for denne oppgaven finner du her: patterns/observable/ObservableListTest.java.