Modulehandleiding Object georiënteerd ontwerpen HE – ICT CP/HIO
Modulehandleiding Object georiënteerd ontwerpen HE – ICT CP/HIO
Modulehandleiding Object georiënteerd ontwerpen HE – ICT CP/HIO
Create successful ePaper yourself
Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.
IG9OGO<br />
Instituut Informatie- en<br />
Communicatietechnologie<br />
<strong>Modulehandleiding</strong><br />
<strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
<strong>HE</strong> <strong>–</strong> <strong>ICT</strong> <strong>CP</strong>/<strong>HIO</strong><br />
(januari 2002: JAN/PRA/VRJ)<br />
versie 3.0<br />
1<br />
1
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Inhoudsopgave<br />
Inhoudsopgave .............................................................................................................................................................2<br />
Introductie....................................................................................................................................................................6<br />
INTRODUCTIE 1: Gebruik van de modulehandleiding <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong> .................................6<br />
Moduleopzet....................................................................................................................................................................6<br />
Introductie per moduletaak..............................................................................................................................................6<br />
Module verwerkingsaktiviteiten......................................................................................................................................6<br />
Terugkoppeling per moduletaak en toetsing van het geheel ...........................................................................................6<br />
INTRODUCTIE 2: Verslaggeving bij de praktikumopdrachten........................................................................6<br />
Planning........................................................................................................................................................................8<br />
Toelichting.................................................................................................................................................................8<br />
Planning per week......................................................................................................................................................8<br />
Moduletaak 1: Correct en robuust programmeren ..................................................................................................9<br />
INTRODUCTIE en TAAKOMSCHRIJVING .........................................................................................................9<br />
Voorkennis:.....................................................................................................................................................................9<br />
Taakdoel:.........................................................................................................................................................................9<br />
Oriëntatie:........................................................................................................................................................................9<br />
Verwerking:.....................................................................................................................................................................9<br />
Verdieping:......................................................................................................................................................................9<br />
Zelftoets: .........................................................................................................................................................................9<br />
LEESTEKST: Design by contract ..........................................................................................................................10<br />
Samenvatting.................................................................................................................................................................10<br />
Correctheid....................................................................................................................................................................10<br />
Assertie..........................................................................................................................................................................10<br />
Classinvariant................................................................................................................................................................11<br />
Nut van asserties ...........................................................................................................................................................11<br />
Design-by-contract........................................................................................................................................................12<br />
Design-by-contract : pre- en postcondities....................................................................................................................12<br />
Policy m.b.t. asserties....................................................................................................................................................13<br />
Run-time support...........................................................................................................................................................13<br />
Praktisch gebruik van asserties......................................................................................................................................13<br />
Hoe “ontdek” ik asserties? ............................................................................................................................................14<br />
VALKUILEN................................................................................................................................................................14<br />
UITGEWERKT VOORBEELD .............................................................................................................................15<br />
Voorbeeldopgave asserties:...........................................................................................................................................15<br />
Voorbeelduitwerking asserties: .....................................................................................................................................16<br />
OEFENINGEN moduletaak 1 ................................................................................................................................18<br />
Oefening 1.1 De bus......................................................................................................................................................18<br />
Oefening 1.2 Boekenplank...........................................................................................................................................18<br />
Oefening 1.3 Postorderbedrijf. ......................................................................................................................................19<br />
Oefening 1.4 Postzegelclub...........................................................................................................................................19<br />
ZELFTOETS moduletaak 1....................................................................................................................................21<br />
Moduletaak 2: Afbeelding NIAM analyse naar ontwerp van classes....................................................................22<br />
INTRODUCTIE en TAAKOMSCHRIJVING .......................................................................................................22<br />
Relevante voorkennis ....................................................................................................................................................22<br />
Taakdoel........................................................................................................................................................................22<br />
Oriëntatie.......................................................................................................................................................................22<br />
Verwerking....................................................................................................................................................................22<br />
Verdieping.....................................................................................................................................................................22<br />
Zelftoets ........................................................................................................................................................................22<br />
2
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
LEESTEKST: omzetting van NIAM IGD naar ontwerp van classes .....................................................................23<br />
Ontwerpen m.b.v. NIAM ..............................................................................................................................................23<br />
NIAM en ontwerp .........................................................................................................................................................23<br />
Voorbeeld classes..........................................................................................................................................................24<br />
Verfijning - schrappen van variabelen ..........................................................................................................................25<br />
Beperkingsregels (constraints) ......................................................................................................................................25<br />
Voorbeeld invariant.......................................................................................................................................................25<br />
Voorbeeld constructor ...................................................................................................................................................26<br />
Ontwerpen NIAM - nominalisatie.................................................................................................................................26<br />
Ontwerpen NIAM - n-aire feittypen..............................................................................................................................27<br />
Vereenvoudigen bij omzetting van n-aire feittypen ......................................................................................................28<br />
Ontwerpen NIAM - over identificatie ...........................................................................................................................28<br />
Samenvatting multipliciteit van types ...........................................................................................................................29<br />
Ontwerp en inheritance .................................................................................................................................................29<br />
OEFENINGEN moduletaak 2 .................................................................................................................................31<br />
OEFENING 2.1.............................................................................................................................................................31<br />
OEFENING 2.2.............................................................................................................................................................31<br />
OEFENING 2.3.............................................................................................................................................................31<br />
OEFENING 2.4.............................................................................................................................................................32<br />
OEFENING 2.5.............................................................................................................................................................32<br />
OEFENING 2.6.............................................................................................................................................................33<br />
OEFENING 2.7.............................................................................................................................................................34<br />
OEFENING 2.8.............................................................................................................................................................34<br />
OEFENING 2.8.............................................................................................................................................................35<br />
ZELFTOETS moduletaak 2..................................................................................................................................36<br />
Moduletaak 3: Introductie UML: use cases , class- en sequencediagrams ...........................................................37<br />
INTRODUCTIE en TAAKOMSCHRIJVING .......................................................................................................37<br />
Voorkennis ....................................................................................................................................................................37<br />
Taakdoel........................................................................................................................................................................37<br />
Oriëntatie.......................................................................................................................................................................37<br />
Verwerking....................................................................................................................................................................38<br />
Verdieping.....................................................................................................................................................................38<br />
Zelftoets ........................................................................................................................................................................38<br />
LEESTEKST bij moduletaak 3 : Introductie in UML en Rational Rose2000 ........................................................39<br />
L3.1 Geschiedenis van UML.........................................................................................................................................39<br />
L3.2 Overzicht van UML..............................................................................................................................................40<br />
L3.2.1 Views .................................................................................................................................................................40<br />
L3.2.2 Diagrammen.......................................................................................................................................................41<br />
L3.2.3 Bouwstenen........................................................................................................................................................45<br />
L3.3 Gebruik van Classdiagrams , Use Casediagrams en Sequencediagrams ..............................................................45<br />
L3.3.1 Gebruik van Classdiagrams ...............................................................................................................................45<br />
L3.3.2 Gebruik van Use Case Diagram.........................................................................................................................48<br />
L3.3.3 Gebruik van Sequence Diagram ........................................................................................................................52<br />
UITGEWERKT VOORBEELD Garage Straatdijk BV.........................................................................................55<br />
Opdrachtomschrijving...................................................................................................................................................56<br />
Uitwerking ....................................................................................................................................................................56<br />
NIAM: feittypen en afgeleide feittypen ........................................................................................................................58<br />
Afbeelding naar classes in eerst opzet...........................................................................................................................58<br />
Use Cases bepalen.........................................................................................................................................................60<br />
SequenceDiagram .........................................................................................................................................................63<br />
OEFENINGEN moduletaak 3 ................................................................................................................................65<br />
OEFENING 3.1:............................................................................................................................................................65<br />
OEFENING 3.2: Bankautomaat (uitwerken op het systeem).......................................................................................65<br />
OEFENING 3.3: vervolg van bankautomaat oefening 3.2............................................................................................66<br />
OEFENING 3.4.............................................................................................................................................................66<br />
OEFENING 3.5.............................................................................................................................................................66<br />
ZELFTOETS moduletaak 3....................................................................................................................................67<br />
IG9OGO<br />
3
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 4: Uitbreiding Java taal concepten: interfaces en inheritance (verv.) .............................................68<br />
INTRODUCTIE en TAAKOMSCHRIJVING ........................................................................................................68<br />
Voorkennis ....................................................................................................................................................................68<br />
Taakdoel........................................................................................................................................................................68<br />
Oriëntatie.......................................................................................................................................................................68<br />
Verwerking....................................................................................................................................................................68<br />
Verdieping.....................................................................................................................................................................68<br />
Zelftoets ........................................................................................................................................................................68<br />
LEESTEKST Moduletaak 4: JAVA interface concept , inner class en inheritance (vervolg) . ............................68<br />
Java interface concept..............................................................................................................................................68<br />
Java interface................................................................................................................................................................69<br />
Eigenschappen van Java interfaces ...............................................................................................................................70<br />
Interfaces en vergelijking van objecten: Comparable ...................................................................................................71<br />
Interfaces en kopieën van objecten : Cloneable ............................................................................................................72<br />
Inner class ...............................................................................................................................................................73<br />
Inner class als Java taalconcept.....................................................................................................................................74<br />
Nogmaals: inheritance ............................................................................................................................................74<br />
Abstract class ................................................................................................................................................................74<br />
Opmerkingen over Ontwerpen met interfaces en abstract classes. .........................................................................75<br />
OEFENINGEN moduletaak 4 ................................................................................................................................76<br />
OEFENING 4.1 Toepassingen interfaces in JDK 1.2 ...................................................................................................76<br />
OEFENING 4.2 Overerving (nogmaals).......................................................................................................................76<br />
OEFENING 4.3. Gebruik van Java interface concept...................................................................................................76<br />
OEFENING 4.4 Adressen vergelijken met herdefinitie equals methode .....................................................................77<br />
OEFENING 4.5 Interface Comparable toepassing........................................................................................................78<br />
OEFENING 4.6 Inheritance en interface toepassing (op systeem uitwerken) ..............................................................78<br />
ZELFTOETS moduletaak 4....................................................................................................................................79<br />
Moduletaak 5 : Collections.......................................................................................................................................81<br />
INTRODUCTIE en TAAKOMSCHRIJVING .......................................................................................................81<br />
Voorkennis ....................................................................................................................................................................81<br />
Taakdoel........................................................................................................................................................................81<br />
Oriëntatie.......................................................................................................................................................................81<br />
Verwerking....................................................................................................................................................................81<br />
Verdieping.....................................................................................................................................................................81<br />
Zelftoets ........................................................................................................................................................................81<br />
LEESTEKST: Collecties .........................................................................................................................................82<br />
L5.0 Samenvatting ........................................................................................................................................................82<br />
L5.1 Scheiden van implementatie en zijn interface.......................................................................................................82<br />
L5.2 Standaard collectie types.......................................................................................................................................83<br />
L5.2.1 Set ......................................................................................................................................................................83<br />
L5.2.2 Map....................................................................................................................................................................85<br />
L5.2.3 List .....................................................................................................................................................................88<br />
L5.2.3.1 Stack ...............................................................................................................................................................89<br />
L5.2.3.2 Queue..............................................................................................................................................................91<br />
L5.2.3.3 Sequence .........................................................................................................................................................91<br />
L5.3 De Java Collections Framework (JCF) .................................................................................................................93<br />
L5.3.1 Interface Collection............................................................................................................................................94<br />
L5.3.2 Interface Set .......................................................................................................................................................94<br />
L5.3.3 Interface SortedSet.............................................................................................................................................94<br />
L5.3.4 Interface Comparable, ‘Natural Ordering’.........................................................................................................95<br />
L5.3.5 Interface Comparator .........................................................................................................................................95<br />
L5.3.6 Interface Map.....................................................................................................................................................98<br />
L5.3.7 Interface SortedMap ..........................................................................................................................................98<br />
L5.3.8 Interface List......................................................................................................................................................98<br />
L5.3.9 De Collections class...........................................................................................................................................99<br />
L5.3.10 Legacy, Vector & Hashtable............................................................................................................................99<br />
IG9OGO<br />
4
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
L5.4 De juiste collectie kiezen ....................................................................................................................................100<br />
L5.5 Gelijkheid van objecten ......................................................................................................................................101<br />
L5.6 Optional operations.............................................................................................................................................102<br />
OEFENINGEN moduletaak 5 ..............................................................................................................................103<br />
Oefening 5.1:...............................................................................................................................................................103<br />
Oefening 5.2:...............................................................................................................................................................103<br />
Oefening 5.3:...............................................................................................................................................................103<br />
ZELFTOETS moduletaak 5..................................................................................................................................104<br />
Moduletaak 6: Ontwerpen van collections ............................................................................................................105<br />
INTRODUCTIE en TAAKOMSCHRIJVING .....................................................................................................105<br />
Voorkennis ..................................................................................................................................................................105<br />
Taakdoel......................................................................................................................................................................105<br />
Oriëntatie.....................................................................................................................................................................105<br />
Verwerking..................................................................................................................................................................105<br />
Verdieping...................................................................................................................................................................105<br />
Zelftoets ......................................................................................................................................................................105<br />
LEESTEKST bij moduletaak 6 : Ontwerpen van collections............................................................................106<br />
L6.0 Samenvatting ......................................................................................................................................................106<br />
L6.1 Afleidingen uit de NIAM analyse.......................................................................................................................106<br />
L6.1.1 Analyse leidend tot de keuze van een Set ........................................................................................................106<br />
L6.1.2 Analyse leidend tot de keuze van een Map .....................................................................................................107<br />
L6.1.3 Analyse leidend tot keuze van een Stack .........................................................................................................108<br />
L6.1.4 Analyse leidend tot de keuze van een queue...................................................................................................109<br />
L6.1.5 Analyse leidend tot de keuze van een Sequence .............................................................................................110<br />
L6.2 Implementatie van een stack...............................................................................................................................112<br />
L6.2.1 De werking van de stack..................................................................................................................................112<br />
L6.2.2 Analyse van de Stack.......................................................................................................................................113<br />
L6.2.3 Implementatie van de classes...........................................................................................................................114<br />
L6.2.3 Implementatie van de classes...........................................................................................................................115<br />
L6.3 Analyse van een lijst ...........................................................................................................................................116<br />
L6.3.1 Implementatie van een Lijst.............................................................................................................................118<br />
OEFENINGEN moduletaak 6 .............................................................................................................................123<br />
OEFENING 6.1...........................................................................................................................................................123<br />
OEFENING 6.2...........................................................................................................................................................123<br />
OEFENING 6.3 (Uitwerken op het systeem en inleveren op het werkcollege) ..........................................................123<br />
OEFENING 6.4 (Verdieping) .....................................................................................................................................123<br />
ZELFTOETS bij moduletaak 6 ...................................................................................................................................124<br />
Opdracht 1. Onroerend goed.................................................................................................................................125<br />
Opdracht 2. Paardensport......................................................................................................................................126<br />
BIJLAGE A. UML Quick Reference for Rational Rose 2000............................................................................128<br />
BIJLAGE B. Uitwerkingen van de zelftoetsen.....................................................................................................134<br />
UITWERKING Zelftoets bij moduletaak 1 .........................................................................................................134<br />
UITWERKING Zelftoets bij moduletaak 2 ..........................................................................................................136<br />
UITWERKING Zelftoets bij moduletaak 3 ..........................................................................................................138<br />
UITWERKING Zelftoets bij moduletaak 4 ..........................................................................................................140<br />
UITWERKING Zelftoets bij moduletaak 5 ..........................................................................................................143<br />
UITWERKING Zelftoets bij moduletaak 6 ..........................................................................................................144<br />
Index .........................................................................................................................................................................145<br />
IG9OGO<br />
5
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Introductie<br />
INTRODUCTIE 1: Gebruik van de modulehandleiding <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Moduleopzet<br />
Evenals bij de voorafgaande JAVA-modulen P_J1 en P_J2 is de te verwerken stof ingedeeld in<br />
moduletaken. De modulehandleiding dient als leidraad bij het uitvoeren van deze taken.<br />
Introductie per moduletaak<br />
Per moduletaak is in een introductieparagraaf aangegeven wat de vereiste voorkennis is en hoe<br />
het concrete taakdoel geformuleerd kan worden. In het onderdeel oriëntatie wordt de stof<br />
geplaatst in een groter geheel.<br />
Module verwerkingsaktiviteiten<br />
De activiteiten die kunnen resulteren in een goede verwerking van de stof beginnen reeds bij de<br />
aanwijzingen met betrekking tot de oriëntatie en worden verder uitgewerkt bij verwerking en<br />
verdieping:<br />
Oriëntatie: Hier wordt na een presentatie van de context van het onderwerp van deze taak een<br />
hoeveelheid te bestuderen materiaal aangedragen. Eén of meerdere onderwerpen worden in een<br />
leestekst aangeboden ter bestudering<br />
Verwerking: Na dit bestuderen van de leestekst dient de stof verder verwerkt te worden door het<br />
maken van oefeningen, eventueel voorzoen van toelichting door de docent daar waar dit nodig is.<br />
Enkele van deze oefeningen dienen ook op het systeem te worden uitgewerkt. Een beperkt aantal<br />
uitwerkingen wordt ingeleverd, ter beoordeling.<br />
Verdieping: Dit onderdeel bestaat doorgaans uit extra stof en / of extra oefeningen. De extra stof<br />
behoort niet tot de tentamenstof. De extra oefeningen kunnen wel nuttig zijn voor het tentamen<br />
Practicumopdrachten: In afwijking van de voorafgaande JAVA-modulen zijn de taaktoetsen hier<br />
vervangen door meer integrerende practicumopdrachten, waarin de stof van enkele moduletaken<br />
tot een geheel is verwerkt.<br />
Terugkoppeling per moduletaak en toetsing van het geheel<br />
Zelftoets: Om aan te tonen dat je de oriëntatie en verwerking van de in de taak doorgewerkte stof<br />
beheerst, wordt de moduletaak afgesloten met een individuele toets. Deze dient zelfstandig<br />
uitgevoerd te worden en is voorzien van een terugkoppelmogelijkheid door de in een bijlage<br />
beschikbaar gestelde uitwerking. In deze zelftoetsen is steeds zo direct mogelijk uitgegaan van de<br />
geformuleerde taakdoelen.<br />
Eindbeoordeling: Aan het eind van de module wordt een tentamen als theorietoets afgenomen.<br />
Als je alle moduletaken naar behoren hebt afgewerkt zou je deze toets voldoende moeten kunnen<br />
scoren. Dit tentamenresultaat, samen met de werkcollegeactiviteiten vormen de theoretische, de<br />
beoordeling van de practicumopdrachten de praktische waardering voor de module. Zie verder de<br />
modulebeschrijving op het net. http://www.ict.hen.nl<br />
INTRODUCTIE 2: Verslaggeving bij de praktikumopdrachten<br />
Voor deze module hebben de practicumopdrachten een grotere omvang en een integrerend<br />
karakter. De twee practicumopdrachten zijn onderverdeeld in een aantal voorgeschreven<br />
activiteiten, teneinde een probleem op te lossen. In hoofdlijn is dit aan te geven met<br />
• Analyse<br />
• Ontwerp<br />
• Implementatie<br />
Voor het eerste onderdeel wordt een volledige NIAM analyse gemaakt, uiteindelijk<br />
6
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
resulterend in een IGD. Met een standaard conversie wordt dit analyseresultaat omgezet in een<br />
statisch ontwerp, weergegeven in een UML Class diagram. Bij opdracht 2 worden de dynamische<br />
aspecten toegevoegd met het opstellen en uitwerken van use cases uit een UML Use case<br />
diagram, gespecificeerd in UML Sequence diagrams. Het aldus voltooide ontwerp wordt<br />
vervolgens geïmplementeerd in JAVA.<br />
Verslaggeving<br />
Bij het inleveren van de opdracht wordt een beknopt verslag geëist waarin minimaal het volgende<br />
moet worden opgenomen:<br />
Voorblad: met naam, module, opdrachttitel en datum.<br />
Probleembeschrijving (kort, je eigen verwoording van de opdracht)<br />
Uitwerking van de opdracht in<br />
Een volledige NIAM analyse, met als eindresultaat een IGD<br />
Een volledig ontwerp: class diagram en alleen voor opdracht 2: use case en sequence<br />
diagrams<br />
Een volledige implementatie in JAVA<br />
Evaluatie: tegen welke problemen ben je aangelopen en hoe heb je deze opgelost.<br />
Conclusie<br />
Bijlage: Broncode van de Java implementatie<br />
Let wel, het moet een kort en bondig verslag blijven.<br />
7
Planning<br />
Toelichting<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De aangegeven planning is een standaard planning voor deze module. Overleg met je eigen<br />
docent of hij aanpassingen wil aanbrengen. Aanleiding hiervoor kan bijvoorbeeld de verroostering<br />
van practica en werkcolleges zijn.<br />
Planning per week<br />
WEEK MODULETAAK PRAKTIKUM inleveren<br />
opdracht pract.taak<br />
Wk1 Mtk1<br />
Mtk2a<br />
Ptk1 Ptk1 Analyse<br />
WK2 Mtk2b<br />
Ptk1 Ptk1 Ontwerp<br />
Mtk3a<br />
Usecases ,<br />
classdiagram<br />
WK3 Mtk3b Ptk1 Ptk1<br />
Implementatie<br />
WK4 Mtk3c<br />
Ptk2 Ptk1 Verslag<br />
Mtk4<br />
Ptk2 Analyse<br />
WK5 Mtk5 Ptk2 Ptk2 Ontwerp<br />
Usecases,<br />
Classdiagram,<br />
Sequencediags<br />
WK6 Mtk6 Ptk2 Ptk2<br />
Implementatie<br />
WK7 Oud tentamen Ptk2 Ptk2<br />
Impl. Vervolg<br />
WK8 Uitloop Ptk2 Ptk2<br />
Verslag<br />
8
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Voorkennis:<br />
Taakdoel:<br />
Oriëntatie:<br />
Verwerking:<br />
Verdieping:<br />
Zelftoets:<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 1: Correct en robuust programmeren<br />
Voorkennis P_J2 onderwerp Programming by Contract.<br />
Student leert als voorbereiding op de eerste practicumopdracht oefenen met andere Collections:<br />
Bijvoorbeeld : Map.<br />
Student kent de begrippen:<br />
Asserties, precondities, postcondities<br />
Student kan asserties toepassen, als ontwerper van software en als gebruiker van bestaande<br />
software componenten<br />
Om kwalitatief hoogwaardige software te <strong>ontwerpen</strong> en te implementeren is het concept “Design by<br />
contract” een essentiële leidraad. Betrouwbare software is het einddoel, met als kenmerken:<br />
correctheid en robuustheid. Het eerste geeft aan dat de software “doet wat deze moet doen,<br />
volgens de specs” en het tweede dat de software, onder afgesproken voorwaarden, gegarandeerd<br />
goed functioneert.<br />
“Design by contract” legt de formele overeenkomst, het contract, vast tussen softwareleverancier<br />
en software(ontwerper!)-gebruiker, met de rechten en verplichtingen van beide partijen.<br />
In de practicumsituatie vervult de student beide rollen: immers je maakt zelf in je volledige<br />
programma gebruik van zelfgeschreven onderdelen. Daarmee ben je tegelijkertijd leverancier en<br />
gebruiker.<br />
“Design by contract” is in verschillende vormen te realiseren. De manier waarop het in deze<br />
module wordt toegepast is door het gebruik van asserties, het checken van pre- en postcondities<br />
van een methode en eventuele class-invarianten. In sommige programmeertalen zijn asserties een<br />
standaard onderdeel, in Java niet. Vandaar het gebruik van een “nl.hen.ict” assertieclass definitie.<br />
Een lightweight variant is het vermelden van de afspraken in de vorm van commentaar:<br />
voorwaarden, akties of terug te geven waarde en eventueel aanvullend commentaar. In de praktijk<br />
is dit de meest voorkomende vorm. Echter van gegarandeerde kwaliteit kan dan geen sprake zijn.<br />
Bestudeer de leestekst Design by contract ,pagina 10<br />
Bestudeer het uitgewerkte voorbeeld, pagina 15<br />
In het werkcollege worden in overleg met de begeleidende docent een selectie van de<br />
oefeningen uitgevoerd. Bestudeer voorafgaand aan Oefening 1.2 ev. de Introduktie voor het<br />
gebruik van een Map, in de leestekst L5.2.2 van Moduletaak 5.<br />
De niet geselecteerde oefeningen kunnen als extra oefening worden gemaakt.<br />
Maak ter afronding van deze module de zelftoets en controleer zelf je uitwerking door deze te<br />
vergelijking met die in de bijlage van deze modulehandleiding. Herhaal zonodig enkele oefeningen.<br />
9
LEESTEKST: Design by contract<br />
Samenvatting<br />
Correctheid<br />
Assertie<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
• design by contract<br />
• asserties:<br />
pre- en postcondities<br />
classinvarianten<br />
• vooral pre- (en post)condities zijn belangrijk<br />
• in Java te testen met<br />
Assertion.require (preconditie, “melding indien niet voldaan ”);<br />
Assertion.ensure (postconditie, “melding indien niet voldaan”);<br />
• nut zit in duidelijker ontwerp van software:<br />
wie is verantwoordelijk voor wat?<br />
Correctheid van programmatuur<br />
Principe:<br />
“Design by contract”<br />
Basisidee:<br />
Ontwerper van een class<br />
• formuleert onder welke voorwaarden een methode (procedure/functie) gebruikt<br />
mag worden<br />
(d.m.v. precondities);<br />
• geeft garanties m.b.t. wat de methode doet<br />
(d.m.v. postcondities).<br />
Voorbeeld<br />
• een lamp mag alleen aangeschakeld worden wanneer hij uit is (preconditie)<br />
(met als idee dat je hem niet onnodig aanschakelt);<br />
• na het aanschakelen krijg je ook de garantie dat hij aan is (postconditie).<br />
Soorten asserties<br />
per methode: preconditie (require)<br />
postconditie (ensure)<br />
voor hele class: classinvariant<br />
Een assertie<br />
• is een bewering die altijd waar moet zijn<br />
(dan is de software correct)<br />
• wordt als een boolean-expressie geformuleerd.<br />
Formulering soms lastig:<br />
• soms alleen uit te voeren met behulp van extra (boolean-)functies;<br />
• in enkele gevallen onmogelijk:<br />
in dat geval als commentaar opnemen.<br />
Pre- en postcondities en class-invarianten zijn asserties.<br />
Preconditie<br />
Een preconditie is een assertie waaraan voldaan moet worden voordat een methode<br />
uitgevoerd mag worden.<br />
10
Classinvariant<br />
Nut van asserties<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Postconditie<br />
Assertie die na aanroep van methode geldig is.<br />
Voorbeeld<br />
In de class Lamp<br />
public void doeAan () {<br />
Assertion.require (! isAan (), “Lamp mag niet aan zijn”);//precond.<br />
isAan = true;<br />
Assertion.ensure (isAan (), “Lamp is aan”); //postcond.<br />
}<br />
Bij aanroep (in een andere methode/class):<br />
if (! lampje.isAan()) {<br />
lampje.doeAan();<br />
}<br />
Indien pre- of postconditie niet waar is wordt boodschap afgedrukt.<br />
Classinvariant<br />
Classinvariant specificeert eigenschappen die altijd geldig zijn voor een object beschreven<br />
door die class.<br />
Dit zijn afhankelijkheden tussen variabelen en functies van een class.<br />
Bijvoorbeeld:<br />
Voor een Persoon zal altijd gelden:<br />
(leeftijd >= 0) && (leeftijd
Design-by-contract<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
VOORBEELD ter illustratie: classes Huis en Lamp<br />
class Huis {<br />
private Lamp hangLamp;<br />
// de enige aanwezige lamp in dit huis:<br />
}<br />
public void doeLampAan(){<br />
// Schakelt de lamp aan.<br />
if (! hanglamp.isAan()) {<br />
hangLamp.doeAan ();<br />
}<br />
}<br />
class Lamp {<br />
private boolean aan;<br />
}<br />
public boolean isAan() {// Is de lamp aan?<br />
return aan;<br />
}<br />
public doeAan { // Schakelt de lamp aan.<br />
Assertion.require (!isAan(), “lamp mag niet aan zijn”);<br />
aan = true;<br />
Assertion.ensure (isAan(), “lamp is aan”);<br />
}<br />
Design by contract<br />
• er zijn twee partijen:<br />
de aanroeper en de aangeroepene<br />
• elke partij heeft zijn verantwoordelijkheden én verplichtingen<br />
• wanneer aanroeper zich niet aan de verplichtingen houdt hoeft de aangeroepene ook<br />
niets te garanderen.<br />
Software kan dan crashen of in foute toestand doorgaan.<br />
Terug naar het voorbeeld:<br />
class Huis maakt gebruik van methode<br />
doeAan () van class Lamp:<br />
aanroeper<br />
(hier: Huis )<br />
aangeroepene<br />
(hier: Lamp)<br />
Design-by-contract : pre- en postcondities<br />
recht<br />
(“voordeel”)<br />
Kan na aanroep zeker zijn<br />
dat aan postconditie (isAan)<br />
is voldaan<br />
Kan er zeker van zijn<br />
dat bij aanroep aan<br />
preconditie is voldaan<br />
verplichting<br />
Mag routine alleen aanroepen<br />
als aan preconditie(isUit) is<br />
voldaan<br />
Moet er voor zorgen dat<br />
aan postconditie voldaan<br />
wordt<br />
Preconditie:<br />
in de class van waaruit de methode wordt aangeroepen moet gecontroleerd worden of dit<br />
mag;<br />
Postconditie:<br />
verplichting voor implementatie van de methode zelf;<br />
Class-invariant:<br />
verplichting voor implementatie van alle public methoden aangeroepen class.<br />
Een bewering die geldig moet zijn bij elk gebruik van een object van de class.<br />
Waar moet een fout gezocht worden bij overtreding:<br />
preconditieovertreding:<br />
12
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
fout van de aanroeper (deze had moeten controleren of de omstandigheden van aanroep<br />
correct waren);<br />
postconditie- of classinvariantovertreding:<br />
fout van implementator van methode cq. class.<br />
Policy m.b.t. asserties<br />
Run-time support<br />
• Asserties zó formuleren dat duidelijk is wat de afspraak (contract) tussen aanroeper en<br />
aangeroepene is. Dus ook in documentatie van een methode opnemen !!<br />
• Zo strak mogelijk formuleren.<br />
class Assertion opnemen in software:<br />
import nl.hen.ict.assertion.Assertion;<br />
Tijdens testfase:<br />
Assertiecontrole is actief.<br />
Run-time-systeem “kijkt” mee of aan asserties wordt voldaan.<br />
Tijdens executie:<br />
Assertiecontrole wordt afgezet, door er commentaar van te maken.<br />
(Asserties niet verwijderen! (specificatie))<br />
Voordelen van werken met asserties en ondersteuning door run-time-systeem:<br />
• meer inzicht in wat geïmplementeerd moet worden (specificatie van de software)<br />
• duidelijke scheiding van verantwoordelijkheden<br />
• fouten gemakkelijker op te sporen: run-time-systeem geeft aan waar de fout zit<br />
• productie-software bevat geen run-time controle meer; wel op de juiste plaats de<br />
normale controles<br />
• asserties blijven in sources als commentaar aanwezig<br />
• documentatie<br />
Vergelijk:<br />
functie van rij-instructeur, zolang geen rijbewijs behaald is.<br />
Praktisch gebruik van asserties<br />
Tijdens ontwikkeling van software controle laten uitvoeren op classes die in ontwikkeling zijn.<br />
(A,B,C)<br />
Van classes die direct gebruikt worden precondities gecontroleerd (D, E)<br />
Overige classes kunnen zonder assertiecontrole gebruikt worden. (F, G, H)<br />
G<br />
B<br />
E<br />
A<br />
F<br />
D<br />
C<br />
H<br />
In ontwikkeling:<br />
alle asserties<br />
laten controleren<br />
Direct gebruikt:<br />
precondities<br />
laten controleren<br />
Niet direct gebruikt:<br />
geen assertiecontrole<br />
nodig<br />
13
Hoe “ontdek” ik asserties?<br />
VALKUILEN<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Indien grondig getest en stabiel:<br />
assertiecontrole omzetten in commentaar<br />
Invarianten en pre- en postcondities zijn op de volgende manier te vinden:<br />
vanuit informatieanalyse: als implementatie van constraints;<br />
door systematisch alle methoden na te lopen en daarover uitspraken te doen.<br />
Invarianten:<br />
per variabele nagaan aan welke voorwaarden die moet voldoen;<br />
idem per functie;<br />
voor iedere combinatie van variabelen en methods nagaan welk verband ze hebben.<br />
Precondities:<br />
per procedure (en functie) nagaan onder welke omstandigheden die procedure (functie) mag<br />
worden aangeroepen;<br />
Postconditie:<br />
afvragen wat het gewenste effect van de methode is<br />
Bij het leren gebruiken van asserties treden vaak terugkerende problemen op.<br />
1. Let op dat de berichten Omschrijving moeten zijn van de assertieexpressie zelf:<br />
Voorbeeld :<br />
double wortel(double getal){<br />
Assertion.require (getal>0,” Getal moet groter dan nul zijn”);<br />
// Let op: dit bericht verschijnt als niet aan voorwaarde is voldaan !!<br />
return sqrt(getal);<br />
}<br />
2. Asserties zijn niet bedoeld (en niet geschikt) als user input controle<br />
Voorbeeld van hoe het niet moet: FOUT voorbeeld !!!<br />
double wortel(double getal){<br />
Assertion.require (getal>0,” Getal moet groter dan nul zijn”);<br />
return sqrt(getal);<br />
}<br />
class Appl{<br />
public static void main(String[ ] arg ){<br />
int invoerGetal;<br />
Console.readInt(invoerGetal);<br />
Assertion.require (invoerGetal>0,” Getal moet > 0 zijn”);<br />
// Voldoet niet als controle. Controle blijft nodig ook na<br />
// testfase!<br />
// Volgende controle blijft dan ook onmisbaar en verplicht door<br />
// contract in sqrt<br />
if (invoerGetal>=0){<br />
System.out.println (wortel(invoerGetal));<br />
}<br />
else<br />
System.out.println(“Negatief getal ingevoerd !”);<br />
}<br />
}<br />
}<br />
3. Veronderstel niet dat alle beschikbare packages voldoende getest zijn met asserties<br />
Bij gebruik van door anderen aangeleverde software is enige voorzichtigheid op zijn plaats.<br />
Ook al zijn de precondities helder geformuleerd, dat wil nog niet zeggen dat er ook voldoende<br />
getest is met behulp van asserties. Niet iedere software engineer levert “ingebouwde<br />
betrouwbaarheid en correctheid door een juiste toepassing van Design by Contract”<br />
4. In afgeleide classes is in de constructor geen assertiecontrole mogelijk als eerste<br />
14
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
statement, als er een expliciete aanroep van een superconstructor noodzakelijk is . Java vereist<br />
dat deze altijd als eerste statement optreedt inde constructor van de afgeleide class. In dat<br />
geval is het handig om toch een assertiecontrole in commentaarvorm op te nemen, om op die<br />
manier de preconditie te specificeren.<br />
class Medewerker extends Persoon<br />
{<br />
public Medewerker(String nwNaam) {<br />
// Assertion.require( nwNaam != null, “nwNaam mag niet null zijn”)<br />
super(nwNaam);<br />
………<br />
}<br />
……..<br />
}<br />
class Persoon<br />
{<br />
private String naam;<br />
public Persoon(String nwNaam) {<br />
Assertion.require( nwNaam != null, “nwNaam mag niet null zijn”)<br />
naam= nwNaam;<br />
}<br />
}<br />
UITGEWERKT VOORBEELD<br />
Voorbeeldopgave asserties:<br />
We gaan uit van een class Bank met een Map rekeninghouders en een Map rekeningen. Verder is<br />
er een class Rekeninghouder en een class Rekening.<br />
Een rekeninghouder wordt geïdentificeerd door een naam. Verder kan hij/zij een rekening openen,<br />
geld storten op z’n rekening, geld opnemen van z’n rekening, z’n rekening opheffen, etc.<br />
Een rekening wordt aangeduid met een rekeningnummer en van een rekening wordt o.a. het saldo<br />
bijgehouden.<br />
Vanuit de class Bank worden de diverse administratieve handelingen verricht, zoals het creëren<br />
van rekeningen, en inschrijven van rekeninghouders, het koppelen van rekeninghouders aan<br />
rekeningen, etc.<br />
Hieronder wordt een deel van de classes Bank, Rekeninghouder en Rekening gegeven:<br />
class Bank {<br />
...<br />
private Map rekeninghouders = new HashMap();<br />
// key: String; value: Rekeninghouder<br />
private Map rekeningen = new HashMap();<br />
// key: Integer; value: Rekening<br />
}<br />
class Rekeninghouder {<br />
...<br />
public void open(Rekening deRekening) {<br />
...<br />
}<br />
private String naam;<br />
private Rekening rekening;<br />
}<br />
class Rekening {<br />
...<br />
private int nummer;<br />
}<br />
Schrijf de volgende methoden voor de class Bank:<br />
15
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
boolean rekeninghouderBestaat(String naam)<br />
// zoekt uit of een rekeninghouder al bekend is bij de bank<br />
boolean rekeningBestaat(int nummer)<br />
// zoekt uit of een rekening al bekend is bij de bank<br />
Rekeninghouder geefRekeninghouder(String naam)<br />
// levert de rekeninghouder op met deze naam<br />
// preconditie: rekeninghouder moet bestaan<br />
Rekening geefRekening(int nummer)<br />
// levert de rekening op met dit nummer<br />
// preconditie: rekening moet bestaan<br />
void koppel(String naam, int nummer)<br />
// koppelt een rekening aan een rekeninghouder, indien mogelijk<br />
Voorbeelduitwerking asserties:<br />
Uitwerking assertievoorbeeld:<br />
::::::::::::::<br />
Bank.java<br />
::::::::::::::<br />
import java.util.*;<br />
class Bank {<br />
private Map rekeninghouders = new HashMap();<br />
// key: String; value: Rekeninghouder<br />
private Map rekeningen = new HashMap();<br />
// key: Integer; value: Rekening<br />
public boolean rekeninghouderBestaat(String naam) {<br />
return rekeninghouders.containsKey(naam);<br />
}<br />
public boolean rekeningBestaat(int nummer) {<br />
return rekeningen.containsKey(new Integer(nummer));<br />
}<br />
public Rekeninghouder geefRekeninghouder(String naam) {<br />
return (Rekeninghouder) rekeninghouders.get(naam);<br />
}<br />
public Rekening geefRekening(int nummer) {<br />
return (Rekening) rekeningen.get(new Integer(nummer));<br />
}<br />
public void koppel(String naam, int nummer) {<br />
if (rekeninghouderBestaat(naam) && rekeningBestaat(nummer)) {<br />
Rekeninghouder rekh = geefRekeninghouder(naam);<br />
Rekening rek = geefRekening(nummer);<br />
if (!rekh.heeftRekening())<br />
rekh.open(rek);<br />
else<br />
System.out.println(“Rekeninghouder heeft al rekening”);<br />
}<br />
else<br />
System.out.println(“Rekeninghouder en/of rekening onbekend”);<br />
}<br />
}<br />
::::::::::::::<br />
Rekening.java<br />
::::::::::::::<br />
class Rekening {<br />
}<br />
private int nummer;<br />
public Rekening(int hetNummer) {<br />
nummer = hetNummer;<br />
}<br />
::::::::::::::<br />
Rekeninghouder.java<br />
16
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
::::::::::::::<br />
import nl.hen.ict.assertion.Assertion;<br />
class Rekeninghouder {<br />
}<br />
private String naam;<br />
private Rekening rekening;<br />
public Rekeninghouder(String deNaam) {<br />
Assertion.require(deNaam != null, “Naam mag niet null zijn”);<br />
naam = deNaam;<br />
Assertion.ensure(naam == deNaam, “naam ingevoerd met deNaam”);<br />
}<br />
public void open(Rekening deRekening) {<br />
Assertion.require(!heeftRekening(),”Heeft nog geen rekening”);<br />
rekening = deRekening;<br />
Assertion.ensure(rekening == deRekening,” Rekening is geopend”);<br />
}<br />
public boolean heeftRekening() {<br />
return rekening != null;<br />
}<br />
17
OEFENINGEN moduletaak 1<br />
Oefening 1.1 De bus.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een bus kan door een stad langs een bepaalde route rijden. De route bestaat uit een aantal<br />
straten, in sommige straten is een halte. Een buschauffeur moet ervoor zorgen dat de route correct<br />
gereden wordt.<br />
Gegeven zijn een aantal public procedures en functies van de class Bus:<br />
• boolean inStraatMetHalte() // is er een halte in de straat waar de bus nu is?<br />
• boolean isInGarage() // is de bus in de garage?<br />
• boolean laatsteHalteIsBereikt() // is de bus bij de laatste halte van de route?<br />
• boolean inLaatsteStraat() //is de bus in de laatste straat van zijn route?<br />
• boolean rijdt() // rijdt de bus?<br />
• void verlaatGarage() // de bus rijdt de garage uit en is in de eerste straat van de route<br />
• void rijNaarVolgendeStraat()<br />
• void keerTerugNaarGarage()<br />
• void stop() // zet de bus stil<br />
• void handelHalteAf()<br />
• boolean iemandWilInstappen()<br />
• boolean iemandWilUitstappen()<br />
• boolean isLeeg()<br />
• boolean isVol()<br />
• void laatPassagierInstappen()<br />
• void laatPassagierUitstappen()<br />
• boolean deurIsOpen()<br />
• void openDeur()<br />
• void sluitDeur()<br />
Geef van alle procedures een zo goed mogelijke specificatie met behulp van pre- en postcondities<br />
en beschrijf de class-invariant.<br />
Oefening 1.2 Boekenplank.<br />
Op een boekenplank staan een aantal woordenboeken. Elk van de woordenboeken heeft een<br />
andere doeltaal (bijvoorbeeld Duits, Frans, Engels, etc.). In de woordenboeken staan Nederlandse<br />
woorden met daarachter per woord een vertaling naar de betreffende taal.<br />
Ontwerp een datastructuur voor een systeem dat deze boekenplank representeert.<br />
Bij het creëren van deze boekenplank wordt onderstaand bestand ingelezen.<br />
Het eerste getal geeft het aantal woordenboeken weer, verder wordt per woordenboek (aangeduid<br />
met de betreffende doeltaal) vermeld hoeveel vertaalde woorden er volgen, en vervolgens komen<br />
deze woorden met hun vertaling.<br />
5<br />
Frans<br />
3<br />
NB. Voorafgaand aan de oefeningen 1.2, 1.3 en 1.4 dient de introductie voor het<br />
gebruik van een Map bestudeerd te worden, zoals weergegeven in Moduletaak<br />
5 Leestekst L5.2.2, met een Mapvoorbeeld voor de Supermarkt.<br />
hond chien<br />
kat chat<br />
paard cheval<br />
18
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Engels<br />
4<br />
hond dog<br />
kat cat<br />
paard horse<br />
leeuw<br />
Spaans<br />
2<br />
lion<br />
hond cane<br />
paard caballo<br />
Latijn<br />
2<br />
hond canus<br />
paard equus<br />
Duits<br />
3<br />
hond Hund<br />
kat Katze<br />
paard Pferd<br />
Implementeer de constructor(en) van het ontworpen systeem.<br />
Oefening 1.3 Postorderbedrijf.<br />
(UITWERKEN OP <strong>HE</strong>T SYSTEEM)<br />
Een postorderbedrijf heeft een klantenbestand. Klanten worden door hun naam geïdentificeerd.<br />
Verder is er een magazijn met artikelen waarvan de prijs is vastgelegd. Artikelen worden door een<br />
artikelnummer geïdentificeerd.<br />
Een klant kan een artikel telefonisch bestellen door zijn naam en het artikelnummer op te geven.<br />
Een klant kan, gegeven zijn naam, ook opvragen hoeveel moet worden betaald voor de geplaatste<br />
bestellingen.<br />
Ontwerp en implementeer een systeem waarmee je de administratie van het postorderbedrijf kunt<br />
voeren. Test je systeem door een aantal artikelen te maken en vervolgens enkele klanten te<br />
creëren, die een aantal bestellingen plaatsen en druk van enkele klanten af wat ze nog moeten<br />
betalen. Druk ook af hoeveel de totale schuld is van alle klanten samen.<br />
De classes Klant (deels) en Artikel zijn gegeven (zie /hio/praktikum/i1/OGO/postorder).<br />
Oefening 1.4 Postzegelclub<br />
Een clubje postzegelverzamelaars houdt een administratie bij van zijn leden. Van alle leden wordt<br />
de naam, het adres en de postzegelverzameling bijgehouden. Van postzegels wordt het land van<br />
herkomst, het jaar van uitgifte, de zegelwaarde en de geschatte handelswaarde geregistreerd. Een<br />
deel van de classes Club, Lid en Postzegel is gegeven. Implementeer in Java de volgende<br />
methoden:<br />
a) public boolean bestaatLidMetNaam(String deNaam) in de class Club;<br />
Toelichting: bestaat er in de Map leden een lid met de betreffende naam<br />
b) public Lid geefLidMetNaam(String deNaam) in de class Club;<br />
Toelichting: zoekt in de Map leden naar het lid met de betreffende naam (Preconditie?!)<br />
c) public void ruil(Postzegel eenZegel, String gever, String ontvanger) in de class Club;<br />
Toelichting: zorgt ervoor, dat de genoemde postzegel van de gever naar de ontvanger gaat<br />
d) public Map zegelsPerLand() in de class Lid;<br />
Toelichting: levert een Map met per land een Set van zegels dat het lid heeft uit dat land<br />
class Club {<br />
private Map leden = new HashMap();<br />
// key: String (naam); value: Lid<br />
public Club() { ...}<br />
public boolean bestaatLidMetNaam(String deNaam) {...}<br />
public Lid geefLidMetNaam(String deNaam) {...}<br />
public void ruil(Postzegel eenZegel, String vanNaam,<br />
String metNaam) {...}<br />
...<br />
}<br />
19
IG9OGO<br />
class Lid {<br />
}<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
private String naam;<br />
private String adres;<br />
private Set postzegelverzameling;<br />
public Lid(String deNaam, String hetAdres, Set dePostzegels) {...}<br />
public String getNaam() {<br />
return naam;<br />
}<br />
public Set getVerzameling() {<br />
return postzegelverzameling;<br />
}<br />
public Map zegelsPerLand() {...}<br />
...<br />
class Postzegel {<br />
private String landVanHerkomst;<br />
private int jaarVanUitgifte;<br />
private double zegelwaarde;<br />
private double handelswaarde;<br />
public Postzegel(String hetLand, int hetJaar, double zWaarde,<br />
double hWaarde) {...}<br />
public String getLandVanHerkomst() {<br />
return landVanHerkomst;<br />
}<br />
...<br />
}<br />
20
ZELFTOETS moduletaak 1<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
1. Wat is het doel van het gebruik van asserties?<br />
2. Wat verstaat men onder Design by Contract?<br />
3. Leg het verschil uit tussen pre- en postcondities.<br />
4. Welke rol vervullen asserties in de testfase en in de opleveringsfase?<br />
5. Welke verantwoordelijkheid heeft de “client” ten aanzien van het gebruik van precondities?<br />
6. Ligt de volgende uitspraak toe:<br />
“Asserties zijn niet bedoeld ter vervanging van input controle”<br />
7. Voeg in onderstaande constructor van Persoon een correct gebruik van asserties toe.<br />
/*<br />
persoon registreert gegevens van een patient geidentificeerd door een naam<br />
tevens wordt de geboortedatum bijgehouden en de huisarts van deze patient<br />
*/<br />
class Persoon{<br />
private String naam; //identificatie<br />
private Arts huisArts;<br />
private String gebDatum;<br />
}<br />
public Persoon(String nwNaam, String nwGebDatum){<br />
}<br />
naam= nwNaam;<br />
gebDatum= nwGebDatum;<br />
8. Geef aan hoe op een correcte manier in een hoofdprogramma een Persoon object wordt<br />
aangemaakt volgens het “contract” van vraag 7.<br />
9. Onderstaande codefragment uit het uitgewerkte voorbeeld van deze moduletaak wordt op een<br />
juiste manier “Design by Contract “ toegepast. Licht toe in welke coderegels hiervan sprake is<br />
en leg uit waarom dit een correct gebruik ervan is.<br />
public void koppel(String naam, int nummer) {<br />
if (rekeninghouderBestaat(naam) && rekeningBestaat(nummer)) {<br />
Rekeninghouder rekh = geefRekeninghouder(naam);<br />
Rekening rek = geefRekening(nummer);<br />
if (!rekh.heeftRekening()){<br />
rekh.open(rek);<br />
}<br />
else {<br />
System.out.println(“Rekeninghouder heeft al rekening”);<br />
}<br />
}<br />
else {<br />
System.out.println(“Rekeninghouder en/of rekening onbekend”);<br />
}<br />
}<br />
Controleer tenslotte je uitwerking aan de hand van de uitwerking van deze zelftoets in<br />
Bijlage B van deze modulehandleiding.<br />
21
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 2: Afbeelding NIAM analyse naar ontwerp van classes<br />
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Relevante voorkennis<br />
Taakdoel<br />
Oriëntatie<br />
Verwerking<br />
Verdieping<br />
Zelftoets<br />
Basiskennis Java uit de modulen IG9_PJ1 IG9P_J2 en basiskennis informatieanalyse uit<br />
IG9_IA1, IG9_IA2<br />
De student leert een IGD volgens NIAM omzetten naar een statisch ontwerp van samenhangende<br />
classes:<br />
hanteert standaard omzettingsregels<br />
elk object, elke ternair feittype, elke nominalisatie wordt een class<br />
elke subtypering leidt tot afgeleide classes<br />
attributen op basis van verplichte feittypen worden meegenomen in de constructor<br />
hanteert standaard vereenvoudigingen in een specifieke situatie<br />
geeft resultaten in tekst weer<br />
In veel methodieken voor object <strong>georiënteerd</strong> <strong>ontwerpen</strong> van software wordt de startfase<br />
overgelaten aan de creativiteit van de ontwerper. Het vinden van een geschikte set van classes die<br />
kan dienen als model van een systeem is daarmee een wat vage bezigheid, met niet<br />
noodzakelijkerwijs reproduceerbare resultaten. Enig houvast dat geboden wordt is meestal het<br />
traceren van zelfstandige naamwoorden in een specificatie van het te bouwen systeem, om<br />
daarmee de voor het systeem relevante objecten op te sporen. Gevolg hiervan is dat deze<br />
ontwerpvaardigheid dan vrijwel niet anders te verkrijgen is dan door te leren van kostbare fouten.<br />
ER ZIJN ANDERE MOGELIJK<strong>HE</strong>DEN:<br />
Uitgaande van een NIAM analyse kunnen er voor het omzetten van een analyseresultaat,<br />
bijvoorbeeld in de vorm van een IGD, naar een kwalitatief goed ontwerp van software een aantal<br />
regels gehanteerd worden om tot een ontwerp van classes te komen. Dit leidt tot een standaard<br />
methodiek voor het afbeelden van een NIAM IGD naar een ontwerp van classes.<br />
De leestekst behandelt de belangrijkste elementen hiervan en geeft voorbeelden.<br />
Bestudeer de leestekst van deze moduletaak.<br />
Maak een selectie uit de oefeningen, in overleg met de begeleidende docent.<br />
Maak de nog niet geselecteerde oefeningen<br />
Maak de zelftoets en controleer je uitwerking<br />
22
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
LEESTEKST: omzetting van NIAM IGD naar ontwerp van classes<br />
Ontwerpen m.b.v. NIAM<br />
NIAM en ontwerp<br />
IG9OGO<br />
Ontwerpen vanuit NIAM<br />
• Hoe ontwerp je grote softwaresystemen?<br />
• zo, dat het systeem onderhoudbaar is<br />
• en zo, dat je een reproduceerbaar resultaat hebt<br />
Oplossing:<br />
• Gebruik NIAM als methode voor data-analyse<br />
• Pas een aantal vuistregels toe om tot een ontwerp te komen.<br />
Analyse<br />
• analyseren is “nadenken over probleem”:<br />
• beschrijven wat het systeem moet doen<br />
• maken van keuzes wat het systeem wel/niet moet doen<br />
• m.b.v. NIAM: beschrijven welke gegevens nodig zijn<br />
• m.b.v. UML( zie Moduletaak3): beschrijven welke processen uitgevoerd moeten worden<br />
Ontwerp<br />
• beschrijven hoe de oplossing eruit ziet<br />
• maken van keuzes hoe implementatie wordt<br />
• beschrijving is onafhankelijk van de gekozen taal,<br />
• maar is wel eenvoudig om te zetten in programmeertaal<br />
NIAM biedt een uitstekende basis om tot een goed ontwerp te komen.<br />
Basisregels:<br />
Ieder objecttype wordt in principe een class.<br />
• De identificatie van een NIAM-objecttype wordt een attribuut ,vervolgens<br />
in JAVA een instancevariabele.<br />
Ieder feittype wordt een attribuut, vervolgens in JAVA weer een instance<br />
variabele.<br />
• Een unair feittype wordt een instancevariabele van het type boolean.<br />
• Een één-op-één of een meer-op-één feittype wordt een enkelvoudige<br />
instancevariabele.<br />
• Een één-op-meer of een meer-op-meer feittype wordt een<br />
instancevariabele van het type “collection van ...” met Set<br />
eigenschappen.<br />
Een afleidbaar feittype wordt een operatie , in Java een methode (en wel een<br />
functie).<br />
Voor het beheer van dit alles dient altijd een Admin class als UoD class te<br />
worden toegevoegd met Sets van de hiervoor gevonden objecten<br />
Een HashSet beantwoordt aan de eisen van een Set<br />
Herkennen van enkelvoudig of meervoudig type:<br />
enkelvoudig: aan de kant van het (NIAM)objecttype staat een enkele pijl over de rechthoek,<br />
meervoudig: aan de kant van het (NIAM)objecttype staat geen pijl of een pijl over meer<br />
rechthoeken.<br />
23
Voorbeeld classes<br />
IG9OGO<br />
Land<br />
Diepte<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
L S<br />
De hoofdstad van is <br />
L S<br />
is een stad van <br />
L Z<br />
grenst aan <br />
D Z<br />
heeft gemiddelde meters<br />
Stel een land, een stad en een zee worden geïdentificeerd door een naam; een diepte door een<br />
getal in meters. Een zee is een diepzee wanneer de diepte meer dan 2000 m bedraagt.<br />
Dit leidt tot vier classes:<br />
Land, Stad, Zee en Diepte<br />
Variabelen en functies van de classes<br />
Land<br />
String naam<br />
Stad hoofdstad<br />
Set steden // Stad<br />
Set aangrenzendeZeeen // Zee<br />
Stad<br />
String naam<br />
Land hoofdstadVan<br />
Land ligtIn<br />
Zee<br />
String naam<br />
Set omringendeLanden // Land<br />
Diepte diepte<br />
boolean isDiepzee // functie<br />
Diepte<br />
int aantalMeters<br />
Set zeeen // Zee nl. alle zeeën met deze diepte<br />
Class-invariant voor de class Zee:<br />
isDiepzee == (diepte > 2000)<br />
Hieruit volgt meteen de implementatie van de functie:<br />
public boolean isDiepzee( ){<br />
return (diepte > 2000);<br />
}<br />
Stad<br />
Zee<br />
Z<br />
*<br />
is een diepzee<br />
24
Verfijning - schrappen van variabelen<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Uit nadere analyse, wanneer de procedures beschreven worden, kan blijken dat bepaalde<br />
variabelen niet gebruikt worden.<br />
Deze variabelen kunnen dan geschrapt worden.<br />
Voorbeeld:<br />
Bij Diepte zullen de zeeën (met die diepte) niet bijgehouden worden (dit is veel te onhandig;<br />
waarom?)<br />
Voorbeeld:<br />
Bij Diepte worden de zeeën niet bijgehouden.<br />
Dan blijft over<br />
Diepte<br />
Zee<br />
int aantalMeters<br />
Nu wordt overal Diepte vervangen worden door int<br />
...<br />
int diepte<br />
Beperkingsregels (constraints)<br />
Beperkingsregels leiden tot diverse speciale zaken bij een class.<br />
Uniciteitsregels<br />
leiden tot een al/niet collection-type-object<br />
soort collection moet gekozen worden op grond van gewenst gedrag :<br />
volgorde doet er wel toe: Sequence<br />
volgorde doet er niet toe: Set<br />
In moduletaak 5 en 6 wordt hier dieper op ingegaan.<br />
Verplichtingsregels<br />
leiden tot een constructorvoorschrift<br />
(Een collection-object wordt altijd onmiddellijk aangemaakt maar niet gevuld,<br />
onafhankelijk van een verplichting.)<br />
Overige beperkingsregels en beperkingsregels m.b.t. verzamelingen in NIAM:<br />
leiden in het algemeen tot class-invarianten<br />
leiden soms tot precondities<br />
Voorbeeld invariant<br />
Regel voor vereenvoudigingen :<br />
Wanneer door dit schrappen van variabelen slechts één instancevariabele in<br />
een class overblijft kan doorgaans de naam van de class overal veranderd<br />
worden in de naam van het type van die ene instancevariabele.<br />
Regel voor de constructor:<br />
In de constructor moeten de volgende variabelen een waarde krijgen:<br />
de variabelen die de identificatie bepalen<br />
de variabelen waar een verplichting op staat<br />
25
Voorbeeld constructor<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
(Verplichting impliceert deelverzameling!)<br />
Overzicht<br />
×<br />
class Overzicht<br />
int nummer<br />
Set artikelen // Artikel<br />
Set hogeBtwArtikelen // Artikel<br />
Set lageBtwArtikelen // Artikel<br />
invariant<br />
hogeBtwArtikelen.is_subset (artikelen)<br />
hogeBtwArtikelen.difference(lageBtwArtikelen).isEmpty()<br />
N.B. Bij Artikel is slechts één variabele overzicht nodig<br />
(in plaats van drie).<br />
Bij het eerste voorbeeld:<br />
Land<br />
Land (String nwNaam, String nwHoofdstad)<br />
naam = nwNaam<br />
hoofdstad = nwHoofdstad<br />
Zee<br />
Zee (String nwNaam, int nwDiepte)<br />
naam = nwNaam<br />
diepte = nwDiepte<br />
Bij het vorige voorbeeld:<br />
Overzicht<br />
Overzicht (int nwNummer)<br />
nummer = nwNummer<br />
artikelen = new Set()<br />
hogeBtwArtikelen = new Set()<br />
Overigens is de volgende een functie en geen variabele:<br />
public Set lageBtwArtikelen ( ) {<br />
return (artikelen.difference<br />
(hogeBtwArtikelen));<br />
}<br />
Ontwerpen NIAM - nominalisatie<br />
O A<br />
bevat <br />
172<br />
172<br />
O A<br />
a1<br />
a2<br />
op heeft een hoog BTW-tarief<br />
172 a1<br />
O A<br />
op heeft een laag BTW-tarief<br />
172 a2<br />
Artikel<br />
26
IG9OGO<br />
Voorbeeld:<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
class Plaats<br />
Provincienaam provincie<br />
Plaatsnaam naam<br />
Set bedrijven // Bedrijf<br />
class Bedrijf<br />
String naam<br />
Plaats vestigingsplaats<br />
class Provincienaam<br />
String naam<br />
Set plaatsen // Plaats<br />
class Plaatsnaam<br />
String naam<br />
Set plaatsen // Plaats<br />
Ontwerpen NIAM - n-aire feittypen<br />
Voorbeeld:<br />
Regel i.v.m. nominalisatie:<br />
samengesteld objecttype wordt class<br />
Regel i.v.m. n-aire feittypen (n >= 3)<br />
(ternair, quarternair, etc.):<br />
Feittype behandelen alsof deze genominaliseerd is.<br />
(Wel een geschikte naam voor het objecttype kiezen!)<br />
27
Voorbeeld NIAM- n - aire feittypen:<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Ternair feittype krijgt de naam Bezoek en leidt tot class Bezoek.<br />
class Bezoek<br />
Persoon persoon //identificatie<br />
Datum datum //identificatie<br />
Plaats plaats //identificatie<br />
class Persoon<br />
String naam<br />
Set bezoeken // Bezoek<br />
classes Datum en Plaats: analoog aan Persoon.<br />
Vereenvoudigen bij omzetting van n-aire feittypen<br />
In veel gevallen kan ook bij de omzetting van n-aire feittypen een vereenvoudigde werkwijze<br />
gevolgd worden. In plaats van het creëren van een aparte class hiervoor kan vaak volstaan worden<br />
met het opnemen van een Map in één of meer van de classes met een key en item van de andere<br />
betrokken classes. In bovenstaand voorbeeld: In class Persoon een Map bezoeken met key Datum<br />
en item Plaats.<br />
De formele aanpak, waarbij in elke class van de betrokken objecten een Map wordt gedefinieerd is<br />
vaak overbodig. In bovenstaand voorbeeld zou dit betekenen dat er in de class Datum een Map<br />
bezoeken wordt opgenomen met key Persoon en item Plaats en in de class Plaats een Map<br />
bezoeken met key Persoon en item Datum.<br />
De ontwerper dient zelf kritisch te beoordelen wat wel en niet zinvol hiervan is op basis van de<br />
opdrachtomschrijving.<br />
Ontwerpen NIAM - over identificatie<br />
Bij classes afkomstig van genominaliseerde feittypen en<br />
van classes van n-aire (n>=3) feittypen<br />
is de identificatie van de objecten expliciet aanwezig:<br />
Identificatie wordt bepaald door de uniciteitspijl boven het feittype.<br />
Identificatie in NIAM en creatie van objecten<br />
De identificerende objecten moeten altijd aanwezig zijn c.q. een waarde hebben. Zoals<br />
eerder opgemerkt moeten ze dus in de constructor een waarde krijgen.<br />
TIP : geef in commentaar aan welke instance variabele(n)<br />
identificerend is (zijn).<br />
28
IG9OGO<br />
Voorbeeld , zie bovenstaande IGD :<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Voor Bezoek zijn persoon, datum en plaats identificerend; komen dus in constructor:<br />
class Bezoek<br />
...<br />
public Bezoek (Persoon nwPersoon, Datum<br />
nwDatum, Plaats nwPlaats) {<br />
persoon = nwPersoon;<br />
// etc.<br />
Samenvatting multipliciteit van types<br />
In schema wordt de omzetting van multipliciteit van typen in een IGD naar regels voor class<br />
ontwerp als volgt:<br />
class B<br />
A a;<br />
class B<br />
Set aas; //A<br />
Gebruik van het schema:<br />
Ontwerp en inheritance<br />
Voorbeeld:<br />
class A<br />
B b;<br />
A B<br />
A<br />
B<br />
A B<br />
class A<br />
Set bees; //B<br />
A B<br />
• Zoek in de tabel de juiste figuur op.<br />
• Ga dan naar de buitenkant om bij de classes het juiste type voor de variabele te vinden.<br />
Regel voor subtypering:<br />
Nominalisatie van een unair feittype (subtypering) wordt zo mogelijk<br />
afgebeeld met inheritance:<br />
er ontstaat een afgeleide class<br />
A<br />
B<br />
A B<br />
29
IG9OGO<br />
Persoon<br />
P<br />
is directeur<br />
D.w.z.: “Een directeur is een persoon.”<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
P A<br />
woont op <br />
Directeur<br />
D B<br />
Adres<br />
is directeur van <br />
Bedrijf<br />
class Persoon<br />
String naam<br />
Adres adres<br />
class Directeur extends Persoon<br />
Bedrijf bedrijf // dat hij/zij leidt<br />
class Bedrijf<br />
String naam<br />
Directeur directeur<br />
class Adres<br />
String straatPlaats<br />
Set bewoners // Persoon<br />
30
OEFENINGEN moduletaak 2<br />
OEFENING 2.1<br />
OEFENING 2.2<br />
OEFENING 2.3<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Lampenfabrieken hebben lampen in voorraad die getest kunnen zijn.<br />
Fabriek Lamp<br />
F L L<br />
heeft in voorraad is getest<br />
philips 1<br />
1<br />
philips 2<br />
3<br />
osram 3<br />
Leid classes, variabelen, functies en class-invarianten af.<br />
Beeld het volgende NIAM diagram af op een geschikte class-structuur<br />
gemeente provincie land<br />
G P P L<br />
ligt in ligt in <br />
aantal<br />
G A<br />
heeft inwoners<br />
P<br />
*<br />
A A L<br />
*<br />
heeft inwoners heeft inwoners<br />
Beeld het volgende NIAM diagram af op een geschikte class-structuur<br />
31
OEFENING 2.4<br />
OEFENING 2.5<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Leid classes, variabelen en class-invarianten af en schrijf de bijbehorende constructoren.<br />
Rekening Bedrag<br />
Overzicht<br />
W U<br />
heeft <br />
wedstrijd uitslag<br />
totoformulier T W U<br />
op staat voor een voorspeld<br />
T A<br />
*<br />
aantal<br />
op staan goede voorspellingen<br />
deelnemer<br />
T D D A<br />
*<br />
is ingevuld door doet keer mee<br />
*<br />
D<br />
heeft gewonnen<br />
R B<br />
het saldo van is <br />
123 100.00<br />
456 0.00<br />
789 84.67<br />
007 385.00<br />
O R1 R2 B<br />
bevat een overboeking van van naar <br />
2171AR 123 456 125.00<br />
2171AR 456 789 25.95<br />
4599BS 123 007 87.50<br />
Transformeer het vorige schema naar een schema met één ternair en twee binaire feittypes met<br />
exact dezelfde informatie-inhoud. Leidt dan opnieuw classes en variabelen af.<br />
32
OEFENING 2.6<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Leid uit onderstaand NIAM diagram een geschikte OO-class-structuur af.<br />
naam<br />
film<br />
leerling<br />
met <br />
N<br />
is een leerling<br />
L S<br />
zit op <br />
L K<br />
zit in <br />
L F<br />
koos voor <br />
F K P<br />
koos op <br />
F<br />
heeft gewonnen<br />
F A<br />
heeft stemmen<br />
*<br />
F N<br />
heeft <br />
*<br />
*<br />
school<br />
aantal<br />
plaats<br />
klasjaar<br />
nummer<br />
klas<br />
<br />
K O G<br />
met en is een klas<br />
opleiding<br />
groep<br />
33
OEFENING 2.7<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Leid uit onderstaand NIAM diagram een geschikte OO-class-structuur af.<br />
artikelcode<br />
A S D<br />
bevat van <br />
met artikel<br />
stof<br />
A<br />
identificeert<br />
een artikel<br />
A<br />
is een nonfood_artikel<br />
X<br />
<br />
food_artikel<br />
A<br />
is een food_artikel<br />
A O<br />
heeft als <br />
ex_eeg_artikel<br />
<br />
A<br />
komt van buiten de eeg<br />
A VP<br />
heeft <br />
<br />
A<br />
is duur<br />
A GH<br />
heeft dagen<br />
delen_per_miljoen<br />
gem_houdbaarheid<br />
oorsprong<br />
invoerheffing<br />
A IH<br />
is onderhevig aan <br />
duur_artikel<br />
verkoopprijs<br />
fabrikant<br />
A FK<br />
wordt gemaakt door <br />
34
OEFENING 2.8<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
(UITWERKEN OP SYSTEEM)<br />
Leid classes, variabelen, functies en class-invarianten af.<br />
P A<br />
is huisarts van <br />
Arts<br />
Persoon<br />
P<br />
is arts<br />
P D<br />
is geboren op <br />
A P<br />
Datum<br />
Plaats<br />
heeft gestudeerd in <br />
Implementeer het systeem en test het met drie personen, waarvan er twee arts zijn. Eén arts is<br />
huisarts van de persoon die geen arts is en de artsen zijn elkaars huisarts.<br />
35
ZELFTOETS moduletaak 2<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
1. Welke elementen uit een NIAM IGD worden standaard omgezet naar een class bij afbeelding<br />
naar een ontwerp van classes?<br />
2. Welke constructor-eisen volgen uit een NIAM IGD bij het <strong>ontwerpen</strong> van een class?<br />
3. Wanneer kunnen er in afwijking van de formele afbeelding naar het ontwerp van classes<br />
vereenvoudigingen worden toegepast? Geef een toelichting.<br />
4. Zet het volgende NIAM IGD om naar een ontwerp van classes:<br />
Sitenaam<br />
Site<br />
N L<br />
Land<br />
[NL, DE, CH]<br />
In is een site met<br />
<br />
hen NL<br />
Knoop<br />
Subnet<br />
S SN M<br />
in op is een<br />
netwerkknoop<br />
hen.NL hio bach<br />
Message<br />
K1 K2 T<br />
Machine<br />
M U<br />
Tijdstip<br />
K S<br />
heeft het beheer over in<br />
subnet “hio”<br />
K S<br />
heeft het beheer<br />
over <br />
is bestemd voor <br />
bach@hio.hen.nl \ 12 karel<br />
op is van naar een<br />
bericht verzonden<br />
bach@hio.hen.nl<br />
rome@cs.ibm.de<br />
12<br />
M T<br />
bevat <br />
bach@hio.hen.nl \ 12 hallo<br />
is systeembeheerder<br />
Tekst<br />
Controleer je uitwerking van de zelftoets aan de hand van Bijlage B van deze<br />
modulehandleiding.<br />
User<br />
*<br />
Systeembeheerder<br />
Afgeleid feittype bevat feiten over alle knopen in het subnet “hio”<br />
U<br />
36
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 3: Introductie UML: use cases , class- en sequencediagrams<br />
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Voorkennis<br />
Taakdoel<br />
Oriëntatie<br />
Basiskennis Java uit de modulen IG9_PJ1 IG9P_J2 en basiskennis informatieanalyse uit<br />
IG9_IA1, IG9_IA2<br />
Stof van moduletaken 1 en 2 is afgerond.<br />
Leren kennen van basisbegrippen en hun notatie in UML :<br />
Class Diagrams:<br />
classes<br />
attribuut en methoden specificatie<br />
relaties:<br />
inheritance, associaties en aggregaties<br />
Use Cases:<br />
actor, use case en onderlinge relaties<br />
specificatie use cases volgens sjabloon<br />
use case realizations<br />
Sequence Diagrams:<br />
objecten en messages<br />
OO ontwerp na omzetting NIAM classes uitbreiden op basis van use cases en met behulp<br />
van sequence diagrams<br />
Modellen hebben we leren kennen in de modulen IA1 en IA2 als abstracties die een relevant deel<br />
van de werkelijkheid van een complex probleem weergeven. Voor het bouwen van software spelen<br />
deze modellen een wezenlijke rol: voor kleine systemen lijkt dit wel eens overbodig, zolang het<br />
systeem met niet al te veel regels code te realiseren is. Iedereen zal er mee instemmen dat voor<br />
grotere en meer complexe systemen modellering een absolute noodzaak is. Het opzetten van een<br />
model stelt immers de ontwerper in staat zich te beperken tot hoofdlijnen waarbij het grotere<br />
geheel goed in beeld blijft. Stap voor stap kan er meer detailinformatie aan toegevoegd worden bij<br />
de transformatie van model naar implementatie.<br />
Visuele modellen hebben het voordeel dat ze complexere systemen eenvoudiger te begrijpen<br />
maken en de communicatie vergemakkelijken over de structuur van systemen. Bijkomend voordeel<br />
is dat het documenteren van een systeem op een meer uniforme en volledige wijze kan<br />
plaatsvinden. Notatie speelt hierbij een belangrijke rol en is een voorwaarde voor eenduidige<br />
communicatie. Hierbij kan de Unified Modeling Language (UML) als standaard goede diensten<br />
bewijzen. Sterk punt hiervan is dat deze standaard mogelijkheden beidt voor het hele traject van<br />
analyse naar ontwerp.<br />
Een belangrijke factor is de benodigde tijd voor het analyseren <strong>ontwerpen</strong> en bouwen van<br />
software. Time to market is voor bedrijven een op de voorgrond tredend concurrentieaspect.<br />
Visuele modellen kunnen dan sterk optimaliseren<br />
Al met al helpen goede modellen voor het beter begrijpen van complexe problemen, bevorderen<br />
van de communicatie erover, leiden tot een betere documentatie van de probleemanalyse en<br />
oplossing, en resulteren uiteindelijk in kwalitatief betere <strong>ontwerpen</strong> en implementaties van<br />
software. Het zal niemand verbazen dat daarmee de geproduceerde software ook beter te<br />
onderhouden is. Als tol maken we in deze module gebruik van enkele diagramtechnieken van<br />
Rational Rose 2000. Use cases, classdiagrams en sequencediagrams zullen we leren gebruiken.<br />
Lees de LEESTEKST bij deze moduletaak 3: Introductie in UML en Rational Rose 2000<br />
37
Verwerking<br />
Verdieping<br />
Zelftoets<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Zoek op het systeem de in de leestekst L3.3 aangegeven pdf file op:<br />
/hio/praktikum/i1/OGO/Rose_usingrose.pdf ( een gebruikershandleiding voor Rational<br />
Rose2000)<br />
Bestudeer hierin in ieder geval Chapter 2 Getting started with Rational Rose<br />
Verder eventueel Chapter 6, 7 en 9 : Class, Use Case en Interaction Diagrams<br />
Maak in overleg met de begeleidende docent een selectie uit de oefeningen.<br />
Een verder verkenning van Rational Rose biedt nog veel mogelijkheden, maar let wel op de<br />
juiste prioriteit.<br />
Maak de bij de verwerking nog niet geselecteerde oefeningen<br />
Maak de zelftoets en controleer je eigen oplossingen aan de hand van de uitwerking. Maak<br />
zonodig een herhaling van enkele oefeningen en/of bestudeer opnieuw delen van de<br />
leestekst.<br />
38
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
LEESTEKST bij moduletaak 3 : Introductie in UML en Rational Rose2000<br />
L3.1 Geschiedenis van UML<br />
IG9OGO<br />
In de jaren negentig werden er verschillende methodieken voor de ondersteuning van<br />
softwareontwikkeling met hun eigen set van notaties op de markt gebracht. De 3 populairste: OMT<br />
van Rumbaugh, Booch van Booch en OOSE van Jacobson. Elke methode met zijn specifieke<br />
sterke en zwakke punten:<br />
• OMT (<strong>Object</strong> Modeling Technique) werd bij General Electric ontwikkeld, geïnitieerd door James<br />
Rumbaugh. Deze methode had zijn kracht in de procesbeschrijving voor testen op basis van<br />
een specificatie van de gestelde eisen. Een aantal modellen beschrijven hierin samen het<br />
systeem: objectmodel, dynamisch model, het functionele en het use-case-model. Daardoor<br />
was deze methode sterk in analyse en minder sterk in ontwerp<br />
• Booch heeft het idee gelanceerd om een systeem als een aantal “views” te analyseren. Voor<br />
elke view is een reeks modeldiagrammen beschikbaar. De methoden kende een uitgebreide<br />
reeks van symbolen. De “clouds” waren voor sommige ontwerpers een continue worsteling met<br />
hun creatieve talenten.<br />
• OOSE en <strong>Object</strong>ory stoelen op de visie van Jacobson op object <strong>georiënteerd</strong>e software<br />
ontwikkeling Deze waren sterk in analyseren van gedrag van een systeem, minder sterk in de<br />
overige gebieden. Beide benaderingen zijn gebaseerd op use cases waarin de vereisten van<br />
een systeem vanuit het gezichtspunt van een gebruiker van het systeem worden gedefinieerd.<br />
Met het uitkomen van nieuwe versie van deze methoden bleek er een sterke convergentie plaats te<br />
vinden, terwijl de notaties bleven verschillen. Voor Booch werd een class aangegeven met een<br />
wolksymbool, de beruchte clouds, voor de andere door middel van een rechthoek. Deze verschillen<br />
leiden gemakkelijk tot verwarring. Deze starre handhaving van verschillen in notaties staat bekend<br />
als “ method wars”.<br />
In 1994 begonnen Booch en Rumbaugh toen beiden werkzaam bij Rational Software Corporation<br />
aan UML te werken. Hun doel was het ontwikkelen van een nieuwe methode “Unified Method”, die<br />
de methoden van Booch en OMT moest samenvoegen. Het jaar daarna voegde ook Jacobson zich<br />
bij dit team. Rational had <strong>Object</strong>ive Systems, de ontwikkelaar van <strong>Object</strong>ory aangekocht.<br />
Het besef groeide dat in de eerste plaats een standaard modelleertaal in ontwikkeling was vandaar<br />
de naamswijziging in “Unified Modeling Language”, een veel eenvoudiger doelstelling dan het<br />
<strong>ontwerpen</strong> van een nieuwe methode voor een proces.<br />
In januari 1997 werd een definitieve versie 1.0 uitgebracht van UML. Deze is door de <strong>Object</strong><br />
Management Group (OMG) als een formele standaardisatie aangenomen in juli 1997 .<br />
Onderstaand plaatje vat de historische ontwikkeling van UML samen en geeft de geplande revisies<br />
weer.<br />
39
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Met nadruk wordt erop gewezen dat een modelleertaal iets anders is dan een ontwikkelmethode.<br />
Het voornaamste verschil zit hem in het feit dat een modelleertaal niet beschikt over een proces of<br />
een set van instructies voor het wat, hoe, wanneer en waarom van ontwikkelstappen. Rational<br />
heeft als methode RUP, Rational Unified Process. In de documentatie van Rational Rose2000 is<br />
hier meer over te vinden, met name de verschillende stappen die gevolgd kunnen worden in het<br />
software-ontwikkelproces, met bijbehorende tools en diagramtechnieken.<br />
L3.2 Overzicht van UML<br />
L3.2.1 Views<br />
2001<br />
(planned major revision)<br />
Q3 2000<br />
(planned minor revision)<br />
Q3 1999<br />
Q2 1998<br />
Q3 1997<br />
(OMG Adopted<br />
Technology)<br />
<br />
UML 1.2<br />
<br />
UML 1.1<br />
<br />
UML 1.4<br />
<br />
UML 1.3<br />
<br />
<br />
UML 2.0<br />
<br />
<br />
<br />
<br />
<br />
Other relevant<br />
standards TBA<br />
ISO Publicly<br />
Available<br />
Specifications<br />
(PAS)<br />
Editorial revision<br />
with no significant<br />
technical changes.<br />
UML is erg breed <strong>georiënteerd</strong> en zowel bruikbaar voor het <strong>ontwerpen</strong> van bedrijfsmodellen als<br />
voor het <strong>ontwerpen</strong> van complexe systemen, met als speciaal toepassingsgebied real-time<br />
systemen. Omdat het wenselijk is de basisversie van UML klein te houden, biedt deze niet<br />
voldoende mogelijkheden voor het bestrijken van al deze domeinen. Vandaar dat de basis versie<br />
open-ended ontworpen is, zodat er uitbreidingen op de taal toegevoegd kunnen worden. De<br />
gelaagde architectuur van UML bestaande uit een basisversie met uitbreidingen, ziet er als volgt<br />
uit:<br />
UML kent verschillende invalshoeken om een model weer te geven. Elke view is een abstractie die<br />
bestaat uit verschillende diagrammen. Er is enige variatie in benadering vanuit UML, RUP of<br />
Rational Rose.<br />
De volgende views worden gehanteerd: Use-case view, Logical view, Component view,<br />
Deployment view en Process view<br />
De Use Case view is bewust centraal geplaatst in onderstaande figuur : de methode wordt<br />
40
IG9OGO<br />
dan ook wel “use case driven” genoemd.<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
In de Rational Rose2000 browser zijn de eerste 4 direct terug te vinden:<br />
In de Use-case view wordt de functionaliteit van het systeem weergegeven zoals deze door de<br />
externe gebruikers (actors) wordt waargenomen.<br />
In de Logical view wordt benadrukt hoe de functionaliteit binnen het systeem is ontworpen, zowel in<br />
een statische structuur als wat het dynamische aspect betreft.<br />
In de Component view is de organisatie van de codecomponenten aan de orde: hoe zijn de<br />
verschillende onderdelen gegroepeerd.<br />
De Deployment view is een weergave van de afbeelding van de softwarecomponenten op de<br />
hardware van het al of niet-gedistribueerde systeem<br />
De Process view omvat de processen en threads die het concurrency en synchronisatiemechanisme<br />
van het systeem bepalen. Deze afbeelding is in Rose2000 voor een groot deel terug<br />
te vinden in de Component View met een restant in de Logical view.<br />
L3.2.2 Diagrammen.<br />
Logical view<br />
Deployment<br />
view<br />
Use<br />
Case<br />
view<br />
Component<br />
view<br />
Process view<br />
In het voorgaande is al opgemerkt dat elke view een aantal diagrammen kent voor de weergave<br />
van het model. Een ontwerpdiagram zal dus altijd aan een view worden toegekend en wordt in de<br />
browser weergegeven conform deze hierarchische structuur.<br />
41
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Diagrammen zijn weer te groeperen in structuur en gedrag diagrammen (structure/ behavior)<br />
Structure : class , collaboration, component, deployment.<br />
Behavior: Use case, State en Sequence diagram<br />
Een korte beschrijving van de basis concepten van de diagrammen, met voorbeelden, zonder<br />
gebruiksdetails(zie L3.3 en volgende.):<br />
Use casediagram<br />
In het use case diagram kan een overzicht gegeven worden van de functionaliteit van het systeem<br />
voor een externe gebruiker. In het volgende voorbeeld van een systeem voor een garage zijn in het<br />
diagram een aantal use cases te onderscheiden , elk aangeduid met een ovaal. Bij elke use case<br />
kan één of meer actoren betrokken zijn en omgekeerd. Een actor wordt aangegeven met het<br />
persoonsymbool omdat eindgebruikers van het systeem meestal personen zijn. Overigens kan een<br />
actor ook best een extern systeem zijn dat gebruik maakt van resultaten van het beschouwde<br />
systeem.<br />
Deze Use cases worden doorgaans van een documentatie voorzien in de vorm van een<br />
usecasespecification waarin de basic en alternate flow of events worden aangegeven, een<br />
beschrijving van de akties die samen het gewenste resultaat van de use case leveren. Iedere flow<br />
of events wordt vervolgens uitgewerkt in de usecase realization in een sequence diagram, waarin<br />
de samenwerking tussen de verschillende objecten in het systeem wordt uitgebeeld.<br />
Het eerste document heeft dus een gebruikers- , het tweede een ontwikkelaarsperspectief.<br />
42
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Classdiagram<br />
Een klasse diagram toont de statische structuur van klassen en hun onderlinge samenhang<br />
In het systeem. De samenhang tussen de klassen kan weergegeven worden met associaties,<br />
aggregaties of generalisaties / specialisaties. Met generalisaties / specialisaties kan inheritance in<br />
beeld worden gebracht. Aanvullend kan ook nog gebruik gemaakt worden van dependency<br />
relationships. Naast deze onderlinge samenhang kan ook per klasse de interne structuur worden<br />
weergegeven met in UML terminologie attributen en operaties, overeenkomend met de java<br />
begrippen Instance variables en methods. De toegangsspecificaties zijn met symbolen per attribuut<br />
en methode weergegeven.<br />
In verschillende stadia van het ontwerpproces kan men kiezen welke details worden weergegeven<br />
en welke niet. Aanvankelijk zal vanuit een NIAM analyse alleen een specificatie van instance<br />
variables en constructoren plaatsvinden, later na uitwerking van de use cases in sequence<br />
diagrams kunnen de overige methoden worden toegevoegd.<br />
<strong>Object</strong>diagram<br />
Een objectdiagram is een uitwerking van een class diagram, op basis van vrijwel identieke<br />
symbolen. In feite een momentopname van de uitvoering van het systeem.<br />
Alleen de naamgeving in de kop van een objectrechthoek wijkt af van die in een klasse<br />
rechthoek: een objectnaam wordt onderstreept en wordt na een dubbele punt gevolgd door de<br />
klassenaam. <strong>Object</strong>diagrams kunnen als nadere toelichting dienen van een class diagram.<br />
Bovendien komen objectdiagrams terug in sequence diagrams of de ermee verwante collaboration<br />
diagrams.<br />
Statediagram (nieuwe benaming: state chartdiagram)<br />
Van elke class kan een state diagram worden gespecificeerd. Hierin worden de toestanden<br />
aangegeven waarin een object van een bepaalde klasse zich kan bevinden. Tevens<br />
43
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
worden de gebeurtenissen (“events”) vastgelegd die aanleiding zijn voor de overgang naar een<br />
andere toestand, ook wel een state transition genoemd. Aan deze overgangen kunnen nog<br />
speciale acties worden verbonden. Voor real time systemen spelen deze state diagrams een<br />
essentiële rol. In deze module blijven deze verder buiten beschouwing.<br />
Sequence diagram<br />
Een sequence diagram toont dynamische aspecten van een systeem. Deze kunnen gebruikt<br />
worden voor het uitwerken van een bij een use case geformuleerde flow of events. Het geeft een<br />
beeld van hoe de communicatie tussen de verschillende objecten in het systeem verloopt. De<br />
messages worden getoond in volgorde van verzenden. Verticaal is een tijdas weergegeven zonder<br />
schaal.<br />
Vanwege de koppeling aan een use case is dit element in de browser van Rational Rose2000<br />
ondergebracht als onderdeel van de betreffende use case realization in de Logical View hierarchy<br />
Collaborationdiagram<br />
Het collaborationdiagram is een alternatief voor een sequencediagram. Deze diagrammen kunnen<br />
44
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
1 op 1 op elkaar worden afgebeeld. Het sequence diagram legt de nadruk op de tijdvolgorde, het<br />
collaborationdiagram meer op de onderlinge samenhang van objecten.<br />
Activitydiagram<br />
Voor het specificeren van use cases kan ook gebruik gemaakt worden van activity diagrams.<br />
Bovendien is dit diagram bruikbaar voor het weergeven van de opbouw binnen methoden van een<br />
class. In deze module zullen we daar geen gebruik van maken.<br />
Component View en Deployment View<br />
Deze views kennen geen aparte diagrammen: de views zelf vormen de diagrammen. In <strong>ontwerpen</strong><br />
voor real-time applicaties spelen beide een belangrijke rol: ze bepalen de afbeelding van het<br />
systeem op een target en leggen tevens de randvoorwaarden voor code generatie vast. Hiervoor<br />
verwijzen we naar een vervolgmodule Real-time <strong>Object</strong>georienteerd Ontwerpen.<br />
L3.2.3 Bouwstenen<br />
Nog een stap verder in de detaillering van een model worden de elementaire bouwstenen<br />
gevonden. De modellen die in UML diagrammen worden voorgesteld kunnen opgebouwd worden<br />
uit verschillende groepen bouwstenen:<br />
• Structurele bouwstenen:<br />
De structuur van een systeem legt de objecten vast die gemodelleerd worden. De primaire<br />
relaties tussen deze elementen bestaan uit communicatie en bevattingsrelaties. Ze bestaan<br />
uit de volgende elementen: (NB Realtime specializations: vooruitlopend op module RTOGO)<br />
UML Base classes, interfaces , use cases, components,<br />
nodes<br />
Real-time<br />
Capsules<br />
specializations<br />
• Bouwstenen die systeemgedrag beschrijven<br />
Deze elementen geven het dynamische deel van een model aan, waarin de veranderingen<br />
van de toestanden van een systeem in de tijd aan bod komen<br />
UML Base State machines, interactions<br />
Real-time<br />
specializations<br />
Protocols<br />
• Groeperende elementen<br />
Deze elementen helpen een model overzichtelijk te houden. Er is maar een element voor:<br />
packages<br />
• Bouwstenen voor toelichtingen<br />
Opmerkingen, toelichtingen of beschrijvingen kunnen met notes aangegeven worden.<br />
L3.3 Gebruik van Classdiagrams , Use Casediagrams en Sequencediagrams<br />
/hio/praktikum/i1/OGO/Rose_usingrose.pdf is een gebruikershandleiding voor Rational Rose2000<br />
L3.3.1 Gebruik van Classdiagrams<br />
Is eenmaal de afbeelding gemaakt van een NIAM analyse naar samenhangende classes,<br />
voorlopig in tekst weergegeven, dan is de stap naar een grafische weergave van dit model<br />
opgebouwd uit classes met onderlinge relaties niet zo groot. In Rose2000 is daarvoor het class<br />
diagram beschikbaar. Basiselement hierin is vanzelfsprekend de<br />
weergave van een class.<br />
Een class wordt weergegeven als een rechthoek met enkele<br />
compartimenten.<br />
Van boven naar beneden:<br />
45
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een compartiment voor de naam van de class, met eventueel een extra aanduiding voor een<br />
stereotype, bijvoorbeeld voor een abstract class. Daaronder een vak voor attributen<br />
(in Java: instance variabelen). Tenslotte is er een vak voor operaties (in Java: methoden), inclusief<br />
de constructor(en).<br />
De specificatie van attributen<br />
en operaties kan vanuit de<br />
browser gebeuren met het<br />
“new” menu item of vanuit<br />
een “Open specification”<br />
menuitem van het pop-up<br />
menu in het class diagram<br />
zelf.<br />
De specificatie kent<br />
verschillende tabbladen die vrij<br />
sterk voor zich spreken.<br />
Invoegen van een nieuw<br />
attribuut of nieuwe operatie<br />
gebeurt met “insert” pop-up<br />
menu item in het betreffende<br />
tabblad.<br />
Na invoeging van een attribuut<br />
of operatie kan deze weer<br />
verder gedetailleerd worden<br />
via het eigen “specification”<br />
dialoogvenster ervan.<br />
Voor relaties tussen classes zijn verschillende symbolen beschikbaar: symbool voor generalisatie,<br />
voor associatie en aggregatie en tenslotte<br />
voor afhankelijkheid. Daarnaast is er nog<br />
een mogelijkheid om afhankelijkheden<br />
voor te stellen.<br />
Het is van belang de eerste vier goed te<br />
onderscheiden:<br />
In nevenstaande afbeelding van een<br />
toolbox zoals deze in enigszins<br />
aangepaste vorm aanwezig is voor class<br />
diagrams zijn de verschillen nog eens op<br />
een rij gezet door toelichtingen per<br />
symbool.<br />
Overigens zijn de toolboxes bij de<br />
verschillende diagrammen aan te passen<br />
met de opdracht “customize” uit het popup<br />
menu, bij indrukken van de rechter<br />
muisknop, vandaar de aangepaste vorm.<br />
46
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Onderstaande tabel geeft nog eens het verschil tussen aggregaties en associaties aan:<br />
Kan éénzijdig of tweezijdig karakter hebben, wel/niet beheerd door de Klasse zelf.<br />
associatie<br />
aggregatie<br />
in één richting In beide richtingen<br />
associatie in één richting<br />
aggregatie in één richting<br />
associatie in beide richtingen<br />
aggregatie met terugverwijzing<br />
TOELICHTING:<br />
1. Bij de eenzijdige relaties: A heeft attribuut van B (of attribuut van set van B's)<br />
Associatie: A kent een attribuut van type B maar beheert dit niet.<br />
Bij verdwijnen van A , kan B blijven bestaan<br />
Aggregatie: A beheert een attribuut van type B, of : B is onderdeel van A<br />
Bij verdwijnen van A verdwijnt ook B<br />
NB " wybertje" aan de kant van de beheerder !!<br />
2. Tweezijdige relaties A heeft attribuut van type B , maar ook B heeft<br />
attribuut van Type A<br />
Relaties tussen classes kunnen in Rose2000 ingevoerd worden door het selecteren van een<br />
associatie of aggregatie in de toolbox van het diagram. Vervolgens kan vanaf ClassA naar ClassB<br />
getrokken worden met de muiscursor. Hetzelfde geldt voor het<br />
aangeven van inheritance met een generalisatiesymbool.<br />
Intermezzo (verdieping) :<br />
Aangezien bij deze module de implementatie van het ontworpen<br />
systeem in Java wordt uitgevoerd, kan composition als<br />
verwantschap tussen objecten buiten beschouwing blijven.<br />
Composition is een bijzondere vorm van aggregatie, waarbij de<br />
ene class binnen de andere bestaat. Voor een composition moet<br />
de “containment by value” gekozen worden in plaats van<br />
“containment by reference”<br />
In Java worden objecten altijd “by reference” opgenomen in een<br />
class, waardoor alleen een (normale) aggregatie voorkomt.<br />
In C++ hoeft dat niet het geval te zijn.<br />
Specificatie van relaties, aggregatie- en associatiedetails<br />
Zoals gebruikelijk in Rose2000 kunnen specificaties langs verschillende wegen worden<br />
opgegeven. Allereerst via de Browser door in de Logical View de te specificeren associatie aan te<br />
klikken en vervolgens “Open specification” te selecteren in het bijbehorende pop-up menu. De<br />
andere weg is weer vanuit het class diagram, aanklikken van het symbool voor associatie of<br />
aggregatie, etc.<br />
De volgende gegevens kunnen worden ingevoerd:<br />
• Naam voor de relatie zelf<br />
• Navigabiliteit:<br />
een open pijl geeft hierbij de richting aan waarin men van een class naar een target<br />
class kan gaan. Bij ontbreken van de open pijl kennen beide objecten elkaar en is<br />
verkeer in beide richtingen mogelijk ( Zie ook tabel op deze pagina)<br />
• Naam voor de rol of rollen bij een bidirectionele relatie: rol A is van en rol B is<br />
• Multipliciteiten<br />
47
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
aantal instanties dat betrokken is bij de associatie met aanduidingen :<br />
n voor precies n ,<br />
* voor nul of meer<br />
n .. m voor minstens n, hoogstens m<br />
m.. * voor minstens m<br />
Ter illustratie een voorbeeld:<br />
Bij een order hoort één klant, een klant heeft 0 of meer orders geplaatst. Een klant kent 1 of meer<br />
afleveradressen, en precies één factuuradres.<br />
L3.3.2 Gebruik van Use Case Diagram<br />
Use cases algemeen<br />
Voor de implementatie onafhankelijke beschrijving van de functionaliteit van een systeem zijn use<br />
cases een geschikt hulpmiddel. Dit hulpmiddel beoogt meer: het geeft tevens de grens van het<br />
systeem aan: wat wordt afgehandeld binnen en wat wordt afgehandeld buiten het systeem.<br />
In UML zijn 3 elementen als bouwstenen van use case diagrams aan te geven:<br />
actors, personen of systemen in interactie met het te<br />
ontwikkelen systeem.<br />
een use cases, in een ellipssymbool,<br />
elk een verzameling van door het systeem uitgevoerde<br />
akties die voor één actor een zichtbaar resultaat van waarden<br />
opleveren de relaties ertussen,<br />
associatierelaties tussen een use case en<br />
een actor,<br />
In wat ingewikkelder gevallen komen en ( ook wel aangeduid met<br />
) generalisatierelaties tussen use cases onderling ook nog voor, overeenkomend<br />
met overerving van classes.<br />
48
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
In onderstaand voorbeeld zijn deze “advanced elements” weergegeven:<br />
De generalisatie aangeduid met de stereotype geeft aan dat de usecase is op gebouwd<br />
met behulp van een basis usecase die in meerdere usecases kan voorkomen. Een extends<br />
generalisatie geeft doorgaans aan dat de derived usecase als een exceptional flow of events<br />
optreedt binnen de “base” usecase.<br />
Een volledig uitgewerkt voorbeeld is verderop in deze moduletaak te vinden.<br />
Een use case zoeken.<br />
Om actors te vinden kan men zich de volgende vragen stellen:<br />
• Welke gebruikersgroep heeft ondersteuning van het systeem nodig om hun taak uit te<br />
kunnen voeren?<br />
• Welke gebruikers zijn nodig om de meest voor de hand liggende hoofdtaken van het<br />
systeem uit te voeren?<br />
• Welke gebruikers zijn nodig om secundaire taken van het systeem uit te kunnen voeren:<br />
zoals systeem opstart en onderhoud, bijvoorbeeld door invoer van nieuwe gegevens.<br />
• Zal het systeem interactie vertonen met andere hardware of softwaresystemen?<br />
Dit betekent dat gestart kan worden met eerst te kijken welke personen gebruik zullen maken van<br />
het systeem, en dat vervolgens nagegaan moet worden in welke rol een persoon gebruik maakt<br />
van het systeem. Doorgaans is de rol een goede naam voor de actor. Vervolgens kan nog bekeken<br />
worden welke gegevensuitwisseling met andere systemen nodig is of plaatsvindt.<br />
Voor het vinden van de use cases gelden soortgelijke vragen, te stellen per gevonden actor:<br />
• Wat zijn de primaire taken die de actor van het systeem wil gebruiken?<br />
• Zal de actor gegevens creeren, opslaan, veranderen, verwijderen of lezen in het<br />
systeem?<br />
• Moet de actor het systeem informatie geven over bepaalde gebeurtenissen buiten het<br />
systeem?<br />
• Zal de actor een systeemstart of -afsluiting uitvoeren?<br />
Als derde stap kan gekeken worden welke actor of actoren betrokken zijn bij welke use cases. Eén<br />
actor kan bij meerdere use cases betrokken zijn en omgekeerd kan ook .<br />
In veel gevallen zijn de use cases knoppen of andere keuze elementen in een grafisch user<br />
interface behorend bij het systeem.<br />
Beschrijving van use cases<br />
1. Korte beschrijving<br />
Documentatie van een use case kan in eerste instantie gewoon in tekst plaatsvinden. Het is een<br />
simpele specificatie van de interactie van gebruiker en systeem. De bewoording kan dan ook in de<br />
terminologie van de eindgebruiker. Deze documentatie zal bij selectie van de use case in het<br />
usecasediagram of in de browser in het documentationwindow verschijnen.<br />
De beschrijving dient de volgende punten te omvatten:<br />
• Korte weergave van het doel van de use case<br />
49
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
• Door wie en in welke situatie wordt de use case opgestart<br />
• Wat doet het systeem, nog niet hoe realiseert het systeem deze use case<br />
Onderstaande figuur geeft een voorbeeld van een usecase documentatie in een model met een<br />
usecase Register for Courses:<br />
De invoer hiervan kan in Rose op twee manieren plaatsvinden:<br />
a. via het documentation window bij een geselecteerde use case. ( Openen van Documentation<br />
Window via menu : View <strong>–</strong> Documentation )<br />
b. via de Open specification optie in het pop-up menu van een geselecteerde use case, bij<br />
klikken rechter muisknop. Onder de tab General is ook een documentation TextField<br />
2. Usecase specification<br />
Een uitvoeriger omschrijving maken we met behulp van het usecase specification document. In<br />
bovenstaande figuur is een verwijzing hiernaar te vinden in de browser onder elke use case.<br />
Uitgewerkt in de figuur voor de Register for Courses usecase middels RegisterForCourses.doc.<br />
Use case specification sjabloon<br />
In een use case specification worden de volgende aspecten per use case vastgelegd:<br />
Basic flow of events ( ook wel : main flow of events)<br />
Deze specificatie omschrijft de acties die in de UC ondernomen interactief tussen<br />
gebruiker en systeem als een “HAPPY PATH” ,dwz. met een gewenste afloop. Op<br />
bepaalde voorwaarden kan er vanaf een zekere stap in deze flow een alternatief traject<br />
doorlopen worden. Dit wordt aangegeven als een Alternative flow.<br />
Exceptional flow of events.<br />
Als er een fout optreedt en de usecase daardoor niet verder normaal afgehandeld kan<br />
worden kunnen hiermee de afsluitende actie(s) omschreven worden.<br />
Precondition<br />
Een aanduiding van de voorwaarden waaronder deze usecase gestart kan worden.<br />
Postcondition<br />
Omschrijving van de gevolgen van het uitvoeren van de usecase in de toestand van het<br />
systeem: meestal een aanduiding wat er veranderd is in een aantal variabelen.<br />
50
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De overige onderdelen spreken waarschijnlijk voor zich. In de oorspronkelijke sjabloon kan altijd een<br />
toelichting worden geraadpleegd bij de overeenkomstige onderdelen.<br />
Zie /hio/praktikum/i1/OGO/rup_ucspec.dot of .htm<br />
Model <br />
USECASE # <br />
Revision history<br />
Date Version Description Author<br />
<br />
<br />
Brief description < korte omschrijving van het doel van de UC><br />
Main flow of events Step Action<br />
1 <br />
2<br />
3<br />
< ….><br />
Alternative flow Step condition: Branching Action<br />
1.2a : <br />
Preconditions<br />
Postconditions<br />
Extension points<br />
Voorwaarden waaronder de usecase uitgevoerd mag worden<br />
1 <br />
2 < ……><br />
Flow nr Result<br />
Main Flow 1 < resultaat : wat is er na<br />
(Success End)<br />
afloop veranderd in<br />
systeem><br />
Altern. 1.2a<br />
2 < id . pt 2><br />
Step Errorcondition Use case<br />
1.3 < welke fout> <br />
Bovenstaande tabel is een alternatieve specificatie van een usecase conform het RUP sjabloon<br />
ucsp.dot , maar weergegeven in een tabelvorm. In de directory /hio/praktikum/i1/OGO is deze te<br />
vinden als UCsptabel.doc.<br />
Use cases realiseren<br />
In de realisatie van een use case wordt een volgende stap gezet in de systeemontwikkeling: van<br />
analyse naar ontwerp. De realisatie wordt weergegeven in diagrammen van samenwerkende<br />
objecten. Daarvoor biedt UML een tweetal interaktiediagrammen: collaborationdiagram en<br />
sequencediagram kunnen één op één op elkaar worden afgebeeld. Een sequence diagram<br />
benadrukt het verloop van het berichtenverkeer tussen de in het systeem aanwezige objecten in de<br />
loop van de tijd, terwijl een objectdiagram meer de nadruk legt op het totaalbeeld van het<br />
berichtenverkeer tussen de diverse objecten, terwijl het tijdvolgordeaspect meer<br />
verborgen zit, in de vorm van een berichtennummering.<br />
51
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
In deze module worden de use cases uitgewerkt binnen Use Case Realizations in<br />
sequencediagrams. Het opbouwen van een sequencediagram wordt gedetailleerder behandeld in<br />
L3.3.3.<br />
Met de menu keuze vanuit een geopend en actief sequence diagram: Browse <strong>–</strong> Create<br />
Collaboration Diagram (F5) kan desgewenst een collaboration diagram gegenereerd worden. Na<br />
enige lay-outaanpassingen ontstaat meestal een bruikbaar geheel.<br />
Deze sequencediagrams worden geplaatst in de Logical View onder de package Designmodel in<br />
een subpackage UseCase Realizations met voor elke Usecase een aparte subpackage, met daarin<br />
een sequencediagram per flow of events. Tenslotte kan onder Designmodel nog een<br />
traceabilityoverzicht worden opgenomen waarin de koppeling van UC en UC realization wordt<br />
gevisualiseerd. Onderstaande weergave van een deel van de browser illustreert een en ander.<br />
L3.3.3 Gebruik van Sequence Diagram<br />
Per Use Case kan voor elke flow of events een Sequence Diagram aangemaakt worden in de<br />
overeenkomstige realizationpackage.<br />
Er bestaat een naming convention voor deze sequence diagrams van de usecase realizations<br />
in de volgende vorm:<br />
Naming conventions : - <br />
Voorbeeld: Dispense Money - Basic flow<br />
Flow types : basic (main) , alternate or exceptional<br />
In Rose is het creeren van een nieuw sequence diagram het handigst uit te voeren met menu<br />
keuze Browse <strong>–</strong> InteractionDiagram. Selecteer vervolgens : en kies in het volgende<br />
dialoogkader Diagram Type: Sequence.<br />
Dit kan ook rechtstreeks vanuit de browser: Selecteer de gewenste use case realization en gebruik<br />
het pop-up menu item New <strong>–</strong> Sequence Diagram.<br />
52
IG9OGO<br />
In de volgende figuur is dit weergegeven:<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Vervolgens kunnen in dit nieuwe Sequence Diagram objecten geplaatst worden door classes te<br />
slepen vanuit de Browser. Deze classes zijn ontstaan uit een eerdere afbeelding van een NIAM<br />
IGD naar een ontwerp van classes. Deze classes zijn eerder als onderdeel in het Design Model<br />
package onder de Logical View ingevoerd. Vanuit de Use case View kan vooraf een Actor gesleept<br />
worden die de use case in gang zet. De weergave van de objecten in het Sequence diagram is<br />
met een rechthoek met daaronder een gestippelde lijn: de levenslijn van het object.<br />
De objectaanduiding kan op 3 manieren plaatsvinden:<br />
• alleen met de naam van het object zelf<br />
• met de naam van het object, een : en vervolgens de naam van de class<br />
• bij afwezigheid van een objectnaam, alleen een dubbele punt gevolgd door de naam van<br />
de class<br />
Kenmerkend is dat objectnamen onderstreept worden.<br />
jan jan : Docent : Docent<br />
Nu is het mogelijk de interactie tussen de verschillende objecten in tijdsvolgorde weer te geven<br />
door de achtereenvolgende berichten in het verkeer tussen de objecten uit te beelden.<br />
Dit gebeurt door in de toolbar (zie volgende pagina) een messagesymbool te selecteren en dit te<br />
plaatsen door te trekken van de levenslijn van het zendende object naar de levenslijn van het<br />
ontvangende object<br />
53
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De berichten tussen de objecten worden met pijlen aangegeven, met als specificatie de<br />
methodenaam en eventueel een nummering om de volgorde, inclusief<br />
eventuele onderlinge afhankelijkheid met behulp van subnummering, nog<br />
eens extra te benadrukken. De nummering kan ingeschakeld worden met<br />
menu Tools <strong>–</strong> Options item, tab Diagram , Display Section: Sequence<br />
Numbering.<br />
Bij het invoeren van de berichten moeten deze na plaatsing<br />
gespecificeerd worden. De rechtermuisknopklik levert hiervoor het<br />
gewenste pop-up menu<br />
Hieirn kan gebruik gemaakt worden van bestaande operations (methods) of kunnen nieuwe<br />
operations ( methods) worden gedefinieerd voor bestaande classes.<br />
Een object kan ook een bericht naar zichzelf versturen: een reflexive message, aangegeven met<br />
een terugkerende pijl symbool. Het object maakt dan gebruik van een eigen method.<br />
NB. Verwijderen van nieuw aangebrachte berichten of objecten moet via een menuselectie<br />
en kan niet met de standaard delete uit een pop-up item. De selectie is: Edit <strong>–</strong> Delete from<br />
model.<br />
Ook actoren kunnen in het sequence diagram worden opgenomen: zij zullen immers vaak de<br />
initiator van het uitvoeren van een usecase zijn. In onderstaand voorbeeld uit de UML tutorial van<br />
Rose is dit aangegeven.<br />
Het eerder geintroduceerde begrip scenario als een globale beschrijving van een use case in de<br />
terminologie van een eindgebruiker, ontmoet hier een tweede betekenis. Ook de uitwerking van<br />
een use case instantie, namelijk voor een bepaalde flow of events, in een<br />
sequencediagram wordt wel als scenario voorgesteld .<br />
54
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
NB In bovenstaand voorbeeld zijn de “balkjes” , de aanduidingen voor het aktief zijn van een<br />
methode op een deel van de levenslijn van een object , in Rose terminologie benoemd als focus<br />
of control niet weergegeven. Deze optie kan worden weergegeven met de menukeuze Tools-<br />
Options- tab Diagram- area Display- field Focus of control . In ditzelfde Display area van de tab<br />
Diagram kan ook de weergave van Hierarchical Messages worden aan- of uitgezet. Onderstaande<br />
figuur illustreert de weergave van een bericht binnen een ander aktief bericht, met ingeschakelde<br />
hierarchical messages. Er verschijnen dan “subbalkjes”.<br />
UITGEWERKT VOORBEELD Garage Straatdijk BV<br />
55
Opdrachtomschrijving<br />
Uitwerking<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
In deze opgave gaat het om een administratief systeem voor een garagebedrijf.<br />
In deze garage werken een monteur, een receptionist en een magazijnbediende.<br />
De receptionist ontvangt de klanten en spreekt met hen af wat er moet gaan gebeuren aan hun<br />
auto (grote/ kleine beurt, uitlaat vervangen, nieuwe banden monteren, etc.). Dit wordt opgeslagen<br />
in het administratiesysteem.<br />
De monteur voert de afgesproken werkzaamheden uit en registreert de tijd die hij eraan besteedt.<br />
Als er nieuwe onderdelen nodig zijn, worden deze door de monteur opgevraagd bij de<br />
magazijnbediende.<br />
De magazijnbediende zoekt met behulp van het systeem uit of de betreffende onderdelen<br />
voorradig zijn. Als dat zo is, dan overhandigt hij ze aan de monteur en registreert dit in het<br />
systeem. Als een onderdeel niet in voorraad is wordt het besteld bij een groothandel. Bij deze<br />
bestelling wordt de levertijd opgevraagd en in het systeem opgenomen, zodat een nieuwe afspraak<br />
met de klant kan worden gemaakt.<br />
Als de klant de auto weer komt ophalen zal de receptionist hem een rekeningoverzicht<br />
presenteren, waarop de door de monteurs aan de auto bestede tijd (=geld, namelijk EUR 35, - per<br />
uur) en de kosten van de gemonteerde nieuwe onderdelen staan vermeld, alsmede de totale<br />
kosten. Als er onderdelen in bestelling zijn, dan zal de receptionist bovendien een nieuwe afspraak<br />
met de klant maken. Deze afspraken worden ook in de administratie opgenomen.<br />
Alleen voor afgeronde afspraken kan een rekening opgemaakt worden.<br />
Gevraagd:<br />
Maak een NIAM-analyse voor het administratieve systeem en leidt hieruit de classes met hun<br />
variabelen (class diagram).<br />
Breid vervolgens dit ontwerp uit door het herkennen van use cases en de daaruit voortvloeiende<br />
operaties.<br />
Op grond van een NIAM analyse is een IGD te vinden.<br />
OPDRACHTOMSCHRIJVING UITWERKING NIAM<br />
In deze opgave gaat het om een<br />
//Comment : UoD<br />
administratief systeem voor een<br />
//Comment UoD,wel belangrijk voor Use Cases:<br />
garagebedrijf.<br />
// Wie doet wat met het systeem?<br />
In deze garage werken een monteur, een // Mogelijke Actor: monteur, receptionist,<br />
receptionist en een magazijnbediende. // magazijnbediende<br />
De receptionist ontvangt de klanten en //Comment: Receptionist Use case: Actor<br />
spreekt met hen af wat er moet gaan Voorbeeldzinnen:<br />
gebeuren aan hun auto (grote/ kleine Klant Jansen heeft afspraak op datum 3/2/2000<br />
beurt, uitlaat vervangen, nieuwe banden Klant Bakker heeft afspraak op datum 8/2/2000<br />
monteren, etc.). Dit wordt opgeslagen in ====================================<br />
het administratiesysteem.<br />
OPMERKING: het ligt voor de hand deze<br />
afspraak te nominaliseren: een aantal feiten zijn<br />
eraan gekoppeld.<br />
Afspraak : datum voor klant definieert<br />
een afspraak : datum voor klant<br />
Evenzo voor werkorder.<br />
====================================<br />
Werkorder: Taak uitlaatvervangen van afspraak<br />
3/2/2000 voor Jansen is een werkorder.<br />
Werkorder: Taak grote beurt van afspraak<br />
8/2/2000 voor Bakker is een werkorder<br />
OPDRACHTOMSCHRIJVING (vervolg) UITWERKING NIAM (vervolg)<br />
56
IG9OGO<br />
De monteur voert de afgesproken<br />
werkzaamheden uit en registreert de tijd<br />
die hij eraan besteedt. Als er nieuwe<br />
onderdelen nodig zijn, worden deze door<br />
de monteur opgevraagd bij de<br />
magazijnbediende.<br />
De magazijnbediende zoekt met behulp<br />
van het systeem uit of de betreffende<br />
onderdelen voorradig zijn. Als dat zo is,<br />
dan overhandigt hij ze aan de monteur en<br />
registreert dit in het systeem.<br />
Als een onderdeel niet in voorraad is wordt<br />
het besteld bij een groothandel. Bij deze<br />
bestelling wordt de levertijd opgevraagd en<br />
in het systeem opgenomen, zodat een<br />
nieuwe afspraak met de klant kan worden<br />
gemaakt.<br />
Als de klant de auto weer komt ophalen zal<br />
de receptionist hem een rekeningoverzicht<br />
presenteren, waarop de door de monteurs<br />
aan de auto bestede tijd (=geld, nl. EUR<br />
35 per uur) en de kosten van de<br />
gemonteerde nieuwe onderdelen staan<br />
vermeld, alsmede de totale kosten.<br />
Als er onderdelen in bestelling zijn, dan zal<br />
de receptionist bovendien een nieuwe<br />
afspraak met de klant maken. Deze<br />
afspraken worden ook in de administratie<br />
opgenomen. Alleen voor afgeronde<br />
afspraken kan een rekening opgemaakt<br />
worden.<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
//Comment: Monteur: Actor in Use cases:<br />
//registratie tijd en onderdelen opvragen<br />
Aan werkorder grote beurt van afspraak 8/2/2000<br />
voor Bakker is aantal twee uren besteed.<br />
Aan werkorder uitlaatvervangen van afspraak<br />
3/2/2000 voor Jansen is aantal 1 uren besteed.<br />
Voor werkorder grote beurt van afspraak<br />
8/2/2000 voor Bakker is aantal 2 van onderdeel<br />
remblokjes gebruikt<br />
Voor werkorder uitlaat vervangen van afspraak<br />
3/2/2000 voor Jansen is een aantal 1 van<br />
onderdeel uitlaat gebruikt<br />
//Comment : magazijnbediende actor in Use<br />
//cases: onderdelen opvragen en onderdelen<br />
//registreren<br />
Van onderdeel uitlaat is aantal 3 voorradig<br />
Van onderdeel remblokjes is aantal 10 voorradig<br />
//Comment magazijnbedeinde actor in Use case:<br />
// onderdelen bestellen<br />
Bestelling van onderdeel uitlaat op datum<br />
3/2/2000 heeft levertijd van aantal 5 dagen<br />
Bestelling van onderdeel remblokjes op datum<br />
8/2/2000 heeft levertijd van aantal 2 dagen<br />
//Comment : Use case nieuwe afspraak maken<br />
(zie //vervolg)<br />
// Comment: Use case rekening maken<br />
Rekening van afspraak 3/2/2000 voor Jansen<br />
betreft totaal aantal 4 arbeidsuren<br />
Rekening van afspraak 8/2/2000 voor Bakker<br />
betreft totaal aantal 2 arbeidsuren<br />
Aantal 2 van onderdeel remblokjes voor afspraak<br />
8/2/2000 voor Bakker is een rekeningspecificatie.<br />
Aantal 1 van onderdeel uitlaat voor afspraak<br />
3/2/2000 voor Jansen is een rekeningspecificatie.<br />
Rekeningspecificatie 1 uitlaat voor 3/2/2000<br />
Jansen heeft subtotaal van 250.<br />
Rekeningspecificatie 2 remblokjes voor 8/2/2000<br />
Bakker heeft subtotaal 120.<br />
----------------------------------------------------<br />
Nodig hiervoor:<br />
Onderdeel uitlaat heeft prijs 250 euro<br />
Onderdeel remblokje heeft prijs 60 euro<br />
----------------------------------------------------<br />
Rekening van afspraak 3/2/2000 voor Jansen<br />
heeft totaalbedrag 490 euro<br />
Rekening van afspraak 8/2/2000 voor Bakker<br />
heeft totaalbedrag 240 euro<br />
//Comment: Use case nieuwe afspraak maken<br />
//In verband met wel/niet beschikbaar rekening:<br />
Afspraak 8/2/2000 voor Bakker heeft een vervolg<br />
57
NIAM: feittypen en afgeleide feittypen<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Feittypen:<br />
Afspraak = datum voor klant definieert een afspraak: datum < -D> voor klant < -K><br />
Werkorder = Taak van afspraak is een werkorder: taak van afspraak <br />
Aan werkorder is aantal uren besteed<br />
Voor werkorder is aantal van onderdeel gebruikt<br />
Van onderdeel zijn aantal voorradig<br />
Bestelling van onderdeel op datum heeft levertijd van aantal dagen<br />
Onderdeel heeft prijs euro<br />
Afspraak heeft een vervolg<br />
Afgeleide feittypen:<br />
Rekeningspecificatie = Aantal van onderdeel voor afspraak is een<br />
rekeningspecificatie: aantal onderdeel voor afspraak <br />
Rekeningspecificatie heeft subtotaal <br />
Rekening van afspraak heeft totaalbedrag euro<br />
Rekening van afspraak betreft totaal aantal arbeidsuren<br />
Dit leidt tot het volgende IGD:<br />
afspraak<br />
klant datum<br />
K<br />
Afbeelding naar classes in eerst opzet.<br />
D<br />
voor is een afspraak<br />
van is een werkorder<br />
A<br />
A<br />
werkorder<br />
A<br />
T<br />
heeft een vervolg<br />
werkorder<br />
taak<br />
W<br />
W<br />
aan is uren besteed<br />
voor is van gebruikt<br />
A<br />
O<br />
U<br />
onderdeel<br />
en<br />
O<br />
aantal<br />
van is voorradig<br />
O<br />
O<br />
V<br />
D<br />
Bestelling van op <br />
heeft levertijd van dagen<br />
P<br />
A<br />
prijs<br />
58
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Toelichting:<br />
Elk objecttype, dus inclusief de nominalisaties, wordt in principe een class:<br />
Klant , Afspraak, Werkorder, Onderdeel, Datum .<br />
Aantal en prijs worden direct vereenvoudigd tot attributen in betreffende classes.<br />
Ternaire feittypen worden een class:<br />
Voor Werkorder is aantal van onderdeel gebruikt<br />
wordt ook omgezet naar een class : de class MateriaalItem<br />
Bestelling van Onderdeel op datum heeft levertijd aantal dagen<br />
wordt omgezetnaar een class : de class Bestelling<br />
De UoD class is hier aangegeven met de gebruikelijke benaming class Admin<br />
Afbeeldingsresultaat:<br />
class Klant{<br />
String naam; // identificatie<br />
Klant(String nwNaam);<br />
}<br />
class Afspraak{<br />
Datum afspraakDatum; // identificatie<br />
Klant klantnaam; // identificatie<br />
Set werkOrderItems; //WerkOrder<br />
Afspraak (Klant invoerKlantNaam, Datum invoerAfspraakdatum);<br />
}<br />
class WerkOrder{<br />
String taak; // identificatie<br />
Afspraak behorendtotAfspraak;// identificatie<br />
int uren;<br />
Set materiaalSpecs; //MateriaalItem<br />
WerkOrder(String nwTaak, Afspraak nwAfspraak);<br />
}<br />
class Onderdeel{<br />
String onderdeelNaam; // identificatie<br />
int voorraadAantal;<br />
double prijs;<br />
Onderdeel(String nwOnderdeelNaam, int nwAantalVoorraad, double nwPrijs);<br />
}<br />
class GebruikteOnderdelenMapItem{<br />
Onderdeel gebruiktOnderdeel;<br />
int aantal;<br />
GebruikteOnderdelenMapItem(Onderdeel hetGebruikteOndereel, int nwAantal);<br />
}<br />
class Bestelling{<br />
Onderdeel bestelOnderdeel; //identificatie<br />
Datum bestelDatum; // identificatie<br />
int aantalLeverDagen; // verplicht<br />
Bestelling( Onderdeel nwBestelOnderdeel, Datum nwBestelDatum, int<br />
nwAantalLeverDagen);<br />
}<br />
class Admin{<br />
Set afspraken; //Afspraak<br />
Set klanten; //Klant<br />
Set werkOrders; //WerkOrder<br />
Set onderdelen; //Onderdeel<br />
Set bestellingen; //Bestelling<br />
}<br />
In onderstaande figuur is het classdiagram weergegeven van het ontwerp tot nu toe.( De<br />
class KeuzeWindow is een onderdeel voor het UserInterface)<br />
59
Use Cases bepalen<br />
Vervolgens kunnen actors en use cases<br />
gezocht worden. In de eerdere NIAM<br />
analyse is vanuit de<br />
opdrachtomschrijving al direkt een en<br />
ander toegelicht met het oog op het<br />
bepalen van de Use cases van het<br />
garagesysteem. Als Actor treden een<br />
receptionist , een monteur en een<br />
magazijnBediende op. De klant komt<br />
alleen met zijn gegevens in het systeem<br />
voor, maar is uiteraard geen gebruiker<br />
van het systeem. Interactie met andere<br />
systemen is er ook niet.<br />
IG9OGO<br />
Dat levert het nevenstaande Use Case<br />
Diagram op.<br />
Vanuit de Use Case maakRekening<br />
wordt een specificatie opgesteld.<br />
Hierin kunnen één of meer Flow of<br />
events worden uitgwerkt in stappen. In<br />
ieder geval de basic of main flow of<br />
events.<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
stap 1. Geef Admin opdracht maakRekening op basis van klantnaam en afspraakDatum<br />
stap 2. Admin zoekt klant op met klantnaam<br />
60
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
stap 3. Admin zoekt Afspraakgegevens op met klant en datum<br />
stap 4. Admin vraagt afspraak om kosten te berekenen<br />
stap 5. Afspraak haalt bestede uren op<br />
stap 6. Afspraak haalt werkorderitems op<br />
stap 7. Werkorderitem zoekt onderdelenitems op<br />
stap 8. Onderdeelitem zoekt aantal en onderdeel op<br />
stap 9. Onderdeel zoekt prijs op<br />
stap 10. Werkorder berekent subtotaal voor deze onderdelen<br />
stap 11. Admin geeft Afspraak opdracht een specificatie te maken<br />
etc.<br />
Deze gegevens zijn als documentatie op te nemen bij de Use Case conform het eerder besproken<br />
sjabloon voor een use case specificatie, in dit geval voor rekeningMaken.<br />
Op de volgende pagina is dit uitgewerkt voor de use case rekeningMaken.<br />
61
IG9OGO<br />
Model<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Garage_rose2001_4.mdl<br />
USECASE 5<br />
Revision history<br />
rekeningMaken<br />
Date Version Description Author<br />
10/01/2001 0.1 nieuw J. van de Vrie<br />
11/01/2001 0.2 Extensionpoints<br />
toegevoegd<br />
J. van de Vrie<br />
Brief description UC maakt rekening op voor een verrichte service in de garage<br />
Main flow of events Step Action<br />
1 Geef Admin opdracht maakRekening op basis<br />
van klantnaam en afspraakDatum<br />
2 Admin zoekt klant op met klantnaam<br />
3 Admin zoekt Afspraakgegevens op met klant<br />
en datum<br />
4 Admin vraagt Afspraak om kosten te<br />
berekenen<br />
5 Afspraak haalt bestede uren op<br />
6 Afspraak haalt werkorderitems op<br />
7 Werkorderitem zoekt onderdelenitems op<br />
8 Onderdeelitem zoekt aantal en onderdeel op<br />
9 Onderdeel zoekt prijs op<br />
10 Werkorder berekent subtotaal voor deze<br />
onderdelen<br />
11 Admin geeft Afspraak opdracht een<br />
specificatie te maken<br />
Alternative flow Step condition: Branching Action<br />
Preconditions<br />
Postconditions<br />
Extension points<br />
voorwaarden waaronder de usecase uitgevoerd mag worden<br />
1 Klantnaam moet bekend zijn<br />
2 Afspraakgegevens moeten ingevoerd zijn<br />
3 Werkorderitems moeten ingevoerd zijn<br />
4 Onderdeelitem moet ingevoerd zijn<br />
5 Onderdeel moet ingevoerd zijn<br />
6<br />
Flow nr Result<br />
Main Flow<br />
(Success End)<br />
1 Een gespecificeerde<br />
rekening is<br />
geproduceerd<br />
2<br />
Altern. nvt<br />
Step Errorcondition Use case<br />
2 Klant niet in<br />
gevoerd<br />
UC Klant niet ingevoerd<br />
62
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Elke Use case kan tenslotte in de corresponderende Use Case Realization voorzien worden van<br />
een SequenceDiagram.Hieronder is een deel van het Sequencediagram behorend bij de main flow<br />
van rekeningMaken afgedrukt.<br />
SequenceDiagram<br />
Toelichting:<br />
Het SequenceDiagram is vrijwel direkt af te leiden uit de hierboven beschreven basic flow of events<br />
voor de Use Case . Als volgt:<br />
De objecten kunnen geplaatst worden zodra deze een taak te vervullen hebben volgens de<br />
usecase specificatie.<br />
In het voorbeeld kan begonnen worden met de plaatsing van de Actor :receptionist, door<br />
selecteren en slepen vanuit de UsecaseView in de objectbrowser.<br />
63
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Vervolgens kan het object Admin geselecteerd uit de Logical View in dezelfde browser en gesleept<br />
worden naar het nieuwe sequencediagram . Nu kan er een message verstuurd worden door<br />
selectie uit de toolbar van een pijl als symbool voor een message of een terugkerende pijl voor een<br />
message naar het object zelf (reflexive message). Dit laatste is dus een bericht waar geen ander<br />
object bij betrokken wordt.<br />
In bovenstaande uitsnede uit het voorbeeld zijn dus objecten actor :receptionist geplaatst,<br />
vervolgens het object :Admin. Daarna is er een message geplaatst van de actor naar het Admin<br />
object. Hierbij is met het popupmenu een aangemaakt: maakRekening met<br />
parameters van String en Datum type. Bij plaatsing van messages is het van belang op het<br />
rechthoekje te starten. Deze rechthoek (focus of control) is in de verticale tijdlijn (of levenslijn) van<br />
een object een aanduiding voor een actieve methode. Bij ruimtegebrek voor plaatsing van een<br />
message met specificatie vindt dan automatisch verlenging plaats. Bij problemen kan ook het<br />
rechthoekje zelf geselecteerd worden en op de gebruikelijke manieren via de hoekpunten vergroot<br />
of verkleind worden.<br />
Voor het specificeren van de messages is veelal een uitbreiding van de operaties /methodes van<br />
de classes van de geplaatste objecten vereist. Dit kan gebeuren zodra een messagesymbool<br />
geplaatst is. In het bijbehorende pop-up menu kan het item worden geselecteerd.<br />
Een interactieve classuitbreiding is zo mogelijk. In de registratie van de class wordt de message als<br />
een nieuwe methode opgenomen.<br />
Het verwijderen van onjuist geplaatste objecten en messages moet via een menuoptie gebeuren.<br />
Dit kan niet met een delete na selectie. Hiervoor is in het Edit menu het menuitem Delete from<br />
Model of Ctrl-D beschikbaar.<br />
64
OEFENINGEN moduletaak 3<br />
OEFENING 3.1:<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een verzekeringsmaatschappij biedt verschillende soorten Verzekeringen aan: ziektekosten-,<br />
auto-, inboedelverzekeringen enz. Bovenstaande figuur geeft een niet-volledig UML diagram.<br />
Elk van de soorten verzekeringen wordt in één of meer polisvormen aangeboden: de<br />
inboedelverzekering alleen als standaard verzekering , de ziektekosten verzekering als standaard<br />
en als uitgebreide verzekering, de auto als wa, wa plus en casco-verzekering. Het hoogste aantal<br />
polisvarianten per soort is 4.<br />
De verzekeringspolissen worden ook in een pakket aangeboden van willekeurige samenstelling<br />
voor een bepaalde verzekerde, dan geldt een extra pakketKorting. Een pakket bestaat uit minimaal<br />
2 polissen. Ook losse polissen kunnen worden aangeboden, maar dan niet in een pakket en dus<br />
ook niet met extra korting.<br />
a. Vul de multipliciteitsaanduidingen in en geef een toelichting.<br />
b. De relatie tussen Verzekeringsvorm en VerzekeringsPakket is niet als aggregatie<br />
aangegeven . Waarom niet?<br />
OEFENING 3.2: Bankautomaat (uitwerken op het systeem)<br />
Bedrag Rekening<br />
Rekeninghouder<br />
B R<br />
R RH<br />
R P<br />
heeft saldo heeft heeft <br />
En-of-rekening<br />
B R<br />
op staat minimaal R E R<br />
is een heeft als<br />
en-of-rekening mederekeninghouder<br />
Pincode<br />
Het betreft hier een bankautomaat waarbij een rekeninghouder, na zijn rekeningnummer en<br />
pincode te hebben opgegeven het volgende kan doen: het saldo opvragen, geld opnemen, geld<br />
storten, en geld naar een andere rekening overboeken.<br />
Een bankmedewerker moet de automaat kunnen vullen, legen, een nieuwe rekening kunnen<br />
aanmaken en overzichten kunnen produceren.<br />
a. Maak een ontwerp van het systeem d.m.v. een class diagram en voer dit in Rational Rose in.<br />
b. Onderscheid verder actors en use cases en voer een use case diagram in Rational<br />
Rose in.<br />
65
OEFENING 3.3: vervolg van bankautomaat oefening 3.2<br />
OEFENING 3.4<br />
OEFENING 3.5.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Werk uit opgave 3.2 de volgende use cases uit in een Sequence diagram:<br />
- saldo opvragen<br />
- geld naar andere rekening overboeken<br />
- produceer rekeningen overzicht.<br />
Voer een class diagram in van de eerder gemaakte uitwerking van oefening 2.8.<br />
Geef ook de multipliciteiten aan.<br />
a. Maak voor de afgeronde Practicumopdracht Onroerend Goed een Use case diagram en<br />
vul een specificatietabel in volgens het gegeven sjabloon.<br />
b. Werk de use case “eigenaar toevoegen aan eigenarenbestand” uit in de bijbehorende Use<br />
Case Realization met één of meer sequencediagrams, afhankelijk van het aantal flows<br />
waarmee de UC is te specificeren<br />
66
ZELFTOETS moduletaak 3<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
1. Waarom <strong>ontwerpen</strong> we aan de hand van modellen?<br />
2. Welke views vormen de basis van UML modellering in RationalRose? Wat is de betekenis<br />
ervan?<br />
3. Wat zijn associaties en aggregaties? Met welke symbolen zijn deze in UML aan te geven?<br />
4. Wat is het doel van een use case diagram?<br />
5. Wat is het verschil tussen een sequence en een collaboration diagram?<br />
6. Maak een class diagram bij de uitwerking van Zelftoets moduletaak 2 vraag 4.<br />
7. Ontwerp voor de use case “urenInvoeren “ van het Garagevoorbeeld een Sequencediagram<br />
voor de main flow of events.<br />
Controleer weer je uitwerkingen en maak een aanvullende studie van de onderwerpen die<br />
niet goed uit de verf kwamen bij het maken van de toets.<br />
Voor problemen bij het gebruik van Rational Rose voor het maken van de diagrammen is de<br />
volgende, eerder genoemde pdf file mogelijk een goed hulp middel:<br />
/hio/praktikum/i1/OGO/Rose_usingrose.pdf: gebruikershandleiding voor Rational Rose2000.<br />
67
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 4: Uitbreiding Java taal concepten: interfaces en inheritance (verv.)<br />
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Voorkennis<br />
Taakdoel<br />
Oriëntatie<br />
Verwerking<br />
Verdieping<br />
Zelftoets<br />
IG9OGO<br />
Basiskennis Java uit de modulen IG9_PJ1 IG9P_J2 en basiskennis informatieanalyse uit<br />
IG9_IA1, IG9_IA2<br />
Verwerking moduletaken 1 t/m 3<br />
Student:<br />
leert Java interface concept begrijpen en toepassen.<br />
Kent toepassing in Comparable en Cloneable interface<br />
leert het begrip abstract class kennen en gebruiken.<br />
kent begrip inner class.<br />
Als uitbreiding van het OO inheritance mechanisme wordt het begrip abstract class behandeld.<br />
Hiermee wordt de mogelijkheid gecreëerd om implementatie van methoden in een subclass af te<br />
dwingen.<br />
Omdat in Java geen multiple inheritance geïmplementeerd kan worden is een interface een<br />
noodzakelijk aanvullend taalelement in Java. In de praktijk is er vaak behoefte aan een afleiding<br />
van meer dan één class: dus meerdere supers voor één sub. Met interfaces kan vrijwel hetzelfde<br />
bereikt worden als met meervoudige overerving zonder de beruchte complicaties ervan, in de vorm<br />
van complexiteit en inefficiency van de compiler, zoals bijvoorbeeld in C ++ .<br />
Bestudeer de leestekst bij Moduletaak 4<br />
Bestudeer de overeenkomstige stof uit het boek Core Java Volume 1<br />
uit Hoofdstuk 5: blz. 176-180, 182 abstract class<br />
uit Hoofdstuk 6: blz. 229-238 interfaces<br />
Maak de door de begeleidende docent aangegeven selectie uit de oefeningen van de<br />
moduletaak.<br />
Bestudeer uit het Core Java boek de toepassing van een inner class : blz. 238- 242 inner<br />
class to implement an interface.<br />
Als toepassing van interfaces kan vast gekeken worden naar event handling in Hoofdstuk 8 van het<br />
Core Java Boek Volume 1 : blz315-323. Deze stof komt uitvoerig aan bod bij de module inleiding<br />
Grafische User Interfaces.<br />
Maak de zelftoets van deze moduletaak, controleer je uitwerking en plan zonodig een<br />
aanvullende bestudering van deelonderwerpen van deze taak.<br />
LEESTEKST Moduletaak 4: JAVA interface concept , inner class en inheritance (vervolg) .<br />
Java interface concept<br />
68
Java interface<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Veel Java packages zijn opgebouwd met behulp van interfaces. In de JDK wordt er veelvuldig<br />
gebruik van gemaakt. (Zie oefening 1 van deze moduletaak). Ook voor zelf ontworpen software<br />
kan het een handig concept zijn. Wat wordt er onder verstaan?<br />
Een interface kan beschouwd worden als<br />
• een abstract class (zie vervolg), zonder data members, met uitzondering van constanten<br />
• waarin methoden worden vastgelegd door middel van hun “signature”, zonder verdere<br />
definitie.<br />
Het doel van interfaces is een contract vast te leggen over te implementeren methodes:<br />
• Interfaces zijn bedoeld om methoden te ‘erven’ en daardoor bepaald gedrag af te<br />
dwingen<br />
Men zegt dat een class een interface implementeert als de methoden aangegeven in de interface<br />
geïmplementeerd worden in de class. In de class definitie wordt dit volgens de syntax, als in<br />
onderstaand voorbeeld, aangegeven:<br />
Een voorbeeld uit de package java.util:<br />
public class HashSet implements Set {<br />
………<br />
}<br />
De class HashSet verplicht zich hiermee de in de interface Set aangegeven methoden te<br />
implementeren en voldoet derhalve aan het “contract” gedefinieerd in de interface.<br />
Bij dit implementeren is dus sprake van “erven” maar nu niet van een gewone class maar van een<br />
interface. Voor de interface Set gaat dit om een 15-tal methoden. Dit aantal kan ook veel kleiner<br />
zijn. Een tweede voorbeeld, nu uit de package java.lang maakt dit duidelijk:<br />
public class Thread implements Runnable {<br />
………<br />
}<br />
De interface Runnable legt nu alleen de signature van de methode run( ) vast. Deze moet nu in de<br />
class Thread geïmplementeerd worden. Overigens het gebruik van deze class Thread komt pas in<br />
een vervolgmodule aan de orde.<br />
In UML notatie wordt een interface als een class weergegeven met een stereotype <br />
Een implementerende class wordt verbonden met het interface door een gestreepte pijl met open<br />
punt, het “realize symbol”. De rechterfiguur is een alternatieve weergave meestal voor components<br />
of packages gebruikt, die een interface implementeren. Voor classes gebruikt men doorgaans de<br />
linker voorstelling.<br />
Eenvoudig voorbeeld van een eigen interface toepassing<br />
In een programmaontwikkeling waarin voorwerpen van verschillende vorm voorkomen<br />
69
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
kunnen algemene eigenschappen in een superclass worden ondergebracht waarvan de andere<br />
vormen erven. In geval de superclass alleen algemene methoden bevat kan hiervoor beter een<br />
interface worden gedefinieerd.<br />
De interface verplicht nu de implementerende classes te voorzien in een methode inhoud( ) en een<br />
methode toString( ).<br />
Eigenschappen van Java interfaces<br />
1. Allereerst is een interface impliciet public en abstract.<br />
Dat laatste begrip komt in het vervolg van deze leestekst aan de orde. Voorlopig houdt het<br />
alleen in dat er geen instanties van gecreëerd kunnen worden.<br />
Deze eigenschappen mogen expliciet vermeld worden:<br />
public abstract interface ExampleInterface {<br />
// eventuele definities van constanten<br />
//<br />
// method signatures<br />
}<br />
2. Een interface kan ook als typeaanduiding optreden in een declaratie van een object.<br />
Voor bovenstaand voorbeeld:<br />
Vorm tekenVorm;<br />
tekenVorm = new Bol(7);<br />
Of in het eeerdere voorbeeld van een Set interface geïmplementeerd door een HashSet<br />
Set voorbeelden;<br />
voorbeelden = new HashSet( );<br />
3. Ook bij een interface typeaanduiding als onder 2 mag gebruik gemaakt worden van de<br />
instanceof operator, zoals bij gewone classes:<br />
if ( voorbeelden instanceof Set) { ………….}<br />
4. Evenals bij inheritance wordt door middel van dynamic binding bepaald welke definitie van<br />
een methode bij aanroep wordt gebruikt.<br />
In het voorbeeld onder 2 met tekenVorm zal tekenVorm.inhoud( ) in dit voorbeeld de<br />
Bol implementatie van inhoud ( ) gebruiken.<br />
70
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Het gedeclareerde type is immers Vorm maar het actuele type is Bol.<br />
5. Een interface kan zelf afgeleid worden middels overerving van een ander interface.<br />
Het eerder aangehaalde voorbeeld van een Set interface uit de package java.util voldoet hier<br />
aan, door de afleiding van interface Collection:<br />
public abstract interface Set extends Collection {<br />
…………….<br />
}<br />
Let op dat hier dus weer wel extends gebruikt moet worden. Er is immers geen sprake van<br />
implementeren maar van overerving: het contract wordt alleen maar uitgebreid, nog steeds<br />
zonder invulling.<br />
6. Classes kunnen meerdere interfaces tegelijk implementeren, maar slechts van één super<br />
erven, bijvoorbeeld:<br />
public class InvoerScherm extends Frame implements Observable, Comparable { ….}<br />
De verschillende interfaces die geïmplementeerd worden, worden hierbij door een komma<br />
gescheiden.<br />
7. Er bestaan interfaces, tagging interfaces, die geen enkele methode vastleggen: het enige doel<br />
ervan is om te informeren en de operator instanceof te kunnen hanteren. Voorbeeld , zie<br />
vervolg, Cloneable interface.<br />
Interfaces en vergelijking van objecten: Comparable<br />
In de module P_J2 is in Moduletaak1 in de leestekst paragraaf 12 al aandacht besteed aan het<br />
vergelijken van objecten door aanroep van de methode boolean equals(<strong>Object</strong>). Daarmee is het<br />
mogelijk in Collections te controleren op al of niet aanwezig zijn van objecten.<br />
In aanvulling hierop is er in de package java.lang een interface Comparable gedefinieerd waarin<br />
een methode compareTo ( ) wordt vastgelegd. Hiermee is het mogelijk reeksen van gelijksoortige<br />
objecten te ordenen.<br />
public interface Comparable {<br />
public int compareTo(<strong>Object</strong> b );<br />
}<br />
De JDK documentatie geeft voor compareTo( ) de volgende informatie:<br />
public int compareTo(<strong>Object</strong> o)<br />
Compares this object with the specified object for order. Returns a negative integer, zero, or<br />
a positive integer as this object is less than, equal to, or greater than the specified object.<br />
It is strongly recommended, but not strictly required that (x.compareTo(y)==0) ==<br />
(x.equals(y)). Generally speaking, any class that implements the Comparable interface<br />
and violates this condition should clearly indicate this fact. The recommended language is<br />
"Note: this class has a natural ordering that is inconsistent with equals."<br />
Parameters:<br />
o - the <strong>Object</strong> to be compared.<br />
Returns:<br />
a negative integer, zero, or a positive integer as this object is less than, equal to, or greater<br />
than the specified object.<br />
Throws:<br />
ClassCastException - if the specified object's type prevents it from being compared to this<br />
<strong>Object</strong>.<br />
71
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een class waarvan de objecten gesorteerd dienen te worden moet nu de Comparable-interface<br />
implementeren; dus er moet een implementatie zijn van de methode compareTo.<br />
Toepassing van interface Comparable: Een vergelijkbare persoon<br />
De class Persoon kan nu vergelijkbaar (Comparable) gemaakt worden door deze Comparable te<br />
laten implementeren:<br />
class Persoon implements Comparable {<br />
private String naam;<br />
}<br />
public Persoon (String nwNaam) {<br />
naam = nwNaam;<br />
}<br />
public int compareTo (<strong>Object</strong> comparant) {<br />
Assertion.require (<br />
comparant instanceof Persoon,<br />
“argument moet van type Persoon zijn”);<br />
}<br />
return (naam. compareTo<br />
(((Persoon) comparant).naam);<br />
// N.B.<br />
// 1. comparant moet eerst naar een Persoon gecast<br />
// worden, om de naam te pakken te kunnen krijgen.<br />
// 2. compareTo is een methode van String die twee strings vergelijkt.<br />
// String implementeert zelf ook interface Comparable<br />
Nu kunnen we in een eenvoudige applicatie personen vergelijken:<br />
class Appl {<br />
public static void main (String args []) {<br />
Appl appl = new Appl ();<br />
appl.doeAlles ();<br />
}<br />
}<br />
void doeAlles () {<br />
Persoon p1 = new Persoon (“alie”);<br />
Persoon p2 = new Persoon (“bert”);<br />
}<br />
// Met als uitvoer:<br />
// p1 komt voor p2<br />
Interfaces en kopieën van objecten : Cloneable<br />
if (p1.compareTo (p2) < 0) {<br />
System.out.println (“p1 komt voor p2”);<br />
} else {<br />
System.out.println (“p2 komt voor p1”);<br />
}<br />
Als we normaliter een kopie maken van een object wordt er gekopieerd op referentiebasis.<br />
Persoon a = new Persoon(“Jansen”);<br />
Persoon b = a;<br />
// a en b verwijzen nu naar het zelfde object.<br />
Vergelijken van de twee objecten met de operator == levert een referentievergelijking op:<br />
a == b; // Dwz. True als a en b naar hetzelfde object verwijzen<br />
Gevolg van deze kopie op referentiebasis is dat een wijziging via a ook een wijziging van b inhoudt.<br />
a Persoon<br />
String naam Jansen<br />
72
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Voor het creëren van een nieuw object met overeenkomstige instance variabelen als een<br />
oorspronkelijk object, maar met een eigen geheugenopslag biedt de class <strong>Object</strong> de methode<br />
clone( ).<br />
Echter , een buitenbeentje! De methode clone( ) heeft toegangsspecificatie protected, zodat alleen<br />
binnen eigen methoden van een (afgeleide) class gebruik gemaakt kan worden van clone( ).<br />
Daar is een gegronde reden voor: de methode clone( ) van <strong>Object</strong> kan alleen een bit-by-bit kopie<br />
leveren , daar er niet van te voren bekend is welke instance variabelen in een class gedefinieerd<br />
zullen worden.<br />
Resultaat toepassing van clone( ) uit <strong>Object</strong> een “shallow clone”:<br />
Bezwaar : Persoon objecten delen nog steeds de naamstring.<br />
Dat vraagt om herdefinitie van de methode clone( ) in de afgeleide class. Als extra wordt er vereist<br />
dat bij het gebruik van deze clone( ) ook de (lege) interface Cloneable wordt gedefinieerd om te<br />
voorkomen dat er een Exception optreedt bij het gebruik van clone( ). Dit is ingebouwd als extra<br />
beveiliging om er zeker van te zijn dat clone( ) bewust , en hopelijk correct, geherdefinieerd wordt.<br />
Toegepast voor de class Persoon wordt een “deep clone” afgeleverd bij de volgende implementatie<br />
van clone( ):<br />
class Persoon implements Cloneable {<br />
{ ……..<br />
public <strong>Object</strong> clone( ) {<br />
try {<br />
Persoon kopie = (Persoon) super.clone( );<br />
// aanroep <strong>Object</strong>.clone( )<br />
kopie.naam = (String) naam .clone( );<br />
return kopie;<br />
}<br />
catch (CloneNotSupportedException exc) {<br />
return null;<br />
}<br />
}<br />
}<br />
Resultaat: twee volledig onafhankelijke Persoon objecten ieder met eigen naamstring.<br />
Inner class<br />
Inner class als Java taalconcept<br />
a<br />
b<br />
a<br />
b<br />
b<br />
Persoon<br />
String naam<br />
Persoon<br />
String naam<br />
Persoon<br />
String naam<br />
Persoon<br />
String naam<br />
Jansen<br />
Jansen<br />
Jansen<br />
In de Collections zoals die opgenomen zijn in JDK 1.2 wordt gebruik gemaakt van inner classes<br />
Ook voor event handling in programma’s met een grafisch user interface is het soms handig<br />
gebruik te maken van inner classes voor het sturen van de reacties op optredende events.<br />
73
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Hierbij zijn zogenaamde Listenerclasses vaak als inner classes geïmplementeerd. Het gebruik van<br />
aparte zelfstandige classes hiervoor is vaak strijdig met het ontwerpprincipe van “lokaliteit”. De<br />
verantwoordelijkheid voor het beheer ligt immers geheel binnen de klasse. Populair gezegd<br />
betekent “lokaliteit”: iedere aparte verantwoordelijkheid van het systeem als geheel dient zoveel<br />
mogelijk op één plek gerealiseerd te worden, zodat wijziging van deze verantwoordelijkheid op zo<br />
min mogelijk plaatsen tot wijziging van de code leidt.<br />
Voorlopig blijft de behandeling van dit Java taalconcept beperkt tot de syntax en de betekenis<br />
ervan. In Moduletaak 5 wordt dit gebruikt onder andere bij de Comparator interface<br />
Wat is een inner class?<br />
Definitie Een inner class is een class waarvan de definitie binnen die van een andere<br />
(omhullende) klasse staat.<br />
Syntax Syntax is precies hetzelfde als de definitie van een gewone class.<br />
Eigenschappen<br />
* Binnen de inner class definitie zijn ook alle attributen en methoden van de<br />
omhullende class zichtbaar<br />
* Instanties van de inner class kunnen alleen binnen instanties van de omhullende<br />
class bestaan.<br />
Voorbeeld<br />
class OmhullendeKlasse<br />
{<br />
private int x;<br />
BinnenKlasse binnenIn= new BinnenKlasse();<br />
Nogmaals: inheritance<br />
Abstract class<br />
}<br />
class BinnenKlasse<br />
{<br />
int y = x <strong>–</strong>1; // toegang tot attributen OmhullendeKlasse<br />
……<br />
}<br />
………<br />
In het voorgaande is al verschillende keren het begrip abstract class opgedoken.<br />
In een inheritance relatie is het soms niet gewenst dat van de superclass objecten worden<br />
gemaakt.<br />
Een voorbeeld:<br />
Er mogen wel objecten van het type Manager etc gemaakt worden, maar niet van het type<br />
Personeelslid. Deze class dient alleen om gemeenschappelijke variabelen en methoden vast te<br />
leggen.<br />
74
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Syntax en betekenis<br />
Een abstract class wordt alleen aangeduid met het keyword abstract.<br />
De betekenis ervan is dat er geen instanties van deze class aangemaakt kunnen en/of mogen<br />
worden.<br />
Abstracte methoden abstract class<br />
Het is mogelijk dat een superclass een of meer methoden heeft die we niet kunnen<br />
implementeren. Bijvoorbeeld: Stel we kunnen het salaris van een personeelslid niet berekenen,<br />
alleen die van de specifieke personeelsleden, omdat bepaalde gegevens nodig zijn die afhangen<br />
van het soort personeelslid. Toch willen we bij een personeelslid het salaris kunnen berekenen<br />
(dynamic binding). Dan moet de methode berekenSalaris in Personeelslid abstract gedefinieerd<br />
worden. De class Personeelslid wordt daardoor automatisch abstract.<br />
Een class met één of meer abstracte methoden is per definitie een abstract class<br />
Voorbeeld abstract method en dus: abstract class<br />
abstract class Personeelslid {<br />
// variabelen<br />
abstract public void berekenSalaris();<br />
}<br />
class Laborant extends Personeelslid {<br />
// variabelen<br />
public void berekenSalaris() {<br />
// hier komt de implementatie<br />
}<br />
}<br />
Opmerkingen:<br />
De abstracte methode berekenSalaris in Personeelslid heeft geen implementatie; ook geen { en }.<br />
Een abstracte class kan meer dan één abstracte methode bevatten. Er mogen overigens in een<br />
abstract class wel andere methoden voorkomen die wel geïmplementeerd zijn. Dit is overigens<br />
een belangrijk verschil met een Java interface.<br />
Toepassingen.<br />
In veel packages zijn abstract classes terug te vinden. In het vervolg van deze module zullen in<br />
taak 5 bij het behandelen van Collection voorbeelden opnieuw abstract classes naar voren komen.<br />
Opmerkingen over Ontwerpen met interfaces en abstract classes.<br />
Vanuit ontwerpoptiek is er doorgaans sprake van een zinvolle toepassing van een abstract class<br />
als er sprake is van een “ is een ….” relatie ( in Niam van subtypering).<br />
Een interface daarentegen is vaak toepasbaar als er sprake is van een “kan …..” omschrijving om<br />
aan te geven waar objecten van verschillende klassen gemeenschappelijk toe in staat zijn.<br />
Overigens moet opgemerkt worden dat JAVA ook in het eerste geval soms dwingt om toch een<br />
interface te gebruiken in verband met het ontbreken van meervoudige overerving. Als er al sprake<br />
is van een superclass waarvan reeds geërfd wordt is men gedwongen om verdere “is een…”<br />
relaties toch met één of meer interfaces te realiseren.<br />
75
OEFENINGEN moduletaak 4<br />
OEFENING 4.1 Toepassingen interfaces in JDK 1.2<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Ga in de documentatie van de JDK op het systeem na welke interfaces voorkomen in de package<br />
java.util en java.lang.<br />
Ga voor de interface Set en de interface Runnable na hoevel methoden er in een<br />
implementerende class gedefinieerd moeten worden.<br />
OEFENING 4.2 Overerving (nogmaals)<br />
Gegeven is de volgende zelfgedefinieerde klassehiërarchie, waarin Collectie een abstracte klasse<br />
is.<br />
Bag<br />
Verzameling<br />
Collectie<br />
Lijst<br />
Elk van de volgende vier programmafragmenten bevat een fout. Geef nauwkeurig aan wat er fout<br />
is en ook of deze fout door de vertaler of pas tijdens verwerking opgemerkt wordt.<br />
Als de fout hersteld kan worden door het toevoegen van een cast, toon dan ook de verbeterde<br />
versie.<br />
a Collectie collectie = new Collectie();<br />
b Collectie collectie = new Verzameling();<br />
Bag bag = collectie;<br />
c Collectie collectie = new Lijst();<br />
Bag bag = (Bag)collectie;<br />
d Collectie collectie = new Bag();<br />
Verzameling verzameling = (Verzameling)collectie;<br />
OEFENING 4.3. Gebruik van Java interface concept<br />
Gegeven zijn de volgende declaraties van een interface Verlengbaar en van klassen I en T.<br />
interface Verlengbaar<br />
{<br />
void verleng();<br />
String waarde();<br />
}<br />
public class T implements Verlengbaar<br />
{<br />
private String s;<br />
public T(String t)<br />
{<br />
s = t;<br />
}<br />
public void verleng()<br />
{<br />
s = s + s;<br />
}<br />
76
IG9OGO<br />
}<br />
public String waarde()<br />
{<br />
return s;<br />
}<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
public class I implements Verlengbaar<br />
{<br />
private int i;<br />
}<br />
public I(int n)<br />
{<br />
i = n;<br />
}<br />
public void verleng()<br />
/* "verdubbelt" i.<br />
* voorbeelden: als i = 56 dan wordt i 5656;<br />
* als i = 200 wordt i 200200.<br />
*/<br />
{<br />
i = Integer.parseInt("" + i + i);<br />
}<br />
public void verdubbel()<br />
{<br />
i = 2*i;<br />
}<br />
public String waarde()<br />
{<br />
return i + "";<br />
}<br />
Geef voor elk van de volgende codefragmenten aan of dit fragment correct is en zo ja, wat na<br />
afloop de waarde is van de string s. Als het fragment niet correct is, geef dan ook aan waarom niet.<br />
a Verlengbaar v = new Verlengbaar();<br />
v.verleng();<br />
String s = v.waarde();<br />
b Verlengbaar v = new I(43);<br />
v.verleng();<br />
String s = v.waarde();<br />
c Verlengbaar v = new T("xyz");<br />
v.verleng();<br />
String s = v.waarde();<br />
d Verlengbaar v = new I(43);<br />
v.verdubbel();<br />
String s = v.waarde();<br />
OEFENING 4.4 Adressen vergelijken met herdefinitie equals methode<br />
Gegeven is een class Adres:<br />
class Adres {<br />
private String straat;<br />
private int huisnummer;<br />
private String postcode;<br />
private String plaats;<br />
...<br />
}<br />
Een tweetal adressen is gelijk als huisnummer en postcode overeenkomen.<br />
77
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Schrijf de methode public boolean equals(<strong>Object</strong> andere).<br />
De postcode kan ook als volgt worden gemodelleerd met behulp van een class Postcode:<br />
class Postcode {<br />
private int cijfers; // invariant: 1000
ZELFTOETS moduletaak 4<br />
IG9OGO<br />
Geef antwoord op de volgende vragen:<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
1. Wat is een interface in JAVA termen? Noem een voorbeeld van een toepassing.<br />
2. Wat is een abstract class? Wat is het nut hiervan?<br />
3. Zijn een interface en een abstract class uitwisselbaar? Waarom wel/niet?<br />
4. De volgende figuur toont een deel van de componentenhiërarchie uit de awt. Container en<br />
Component zijn abstract classes<br />
Component<br />
Container TextComponent<br />
Panel Window<br />
Dialog Frame<br />
TextArea TextField<br />
Gegeven is bovendien nog het volgende:<br />
− De klasse Container heeft een methode add met de volgende signatuur:<br />
public void add(Component c)<br />
− De klassen Window en Dialog hebben constructoren als volgt:<br />
public Window(Frame parent)<br />
public Dialog(Frame parent)<br />
− Een applicatieprogrammeur definieert in een eigen klasse een methode met de volgende<br />
signatuur:<br />
public void voegLettersToe(TextField tf, Window w)<br />
Elk van de volgende programmafragmenten bevat een fout. Geef aan wat er fout is en<br />
wanneer deze fout optreedt, bij vertaling of bij verwerking. Als de fout vermeden kan worden<br />
door een cast toe te voegen, toon dan ook de verbeterde code. Licht je antwoorden kort toe.<br />
a Component c1 = new Panel();<br />
Component c2 = new Frame();<br />
c2.add(c1);<br />
b Window w = new Frame();<br />
Dialog d = new Dialog(w);<br />
c TextComponent tc = new TextArea();<br />
Frame f = new Frame();<br />
voegLettersToe((Textfield)tc, f);<br />
79
IG9OGO<br />
VERVOLG ZELFTOETS bij moduletaak 4<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
5. Gegeven zijn de volgende klassedefinities.<br />
public class A<br />
{<br />
public int tien(int i)<br />
{ return i+10; }<br />
}<br />
public int twintig(int i)<br />
{ return i+20; }<br />
public class B extends A<br />
{<br />
public int tien(int i)<br />
{ return i*10; }<br />
}<br />
public int superTien(int i)<br />
{ return super.tien(i); }<br />
public class C extends B<br />
{<br />
public int twintig(int i)<br />
{ return i*20; }<br />
}<br />
Geef voor elk van de volgende programmafragmenten aan, of het fragment correct is. Zo<br />
niet, wat is er fout? Zo ja, wat is na afloop de waarde van de variabele resultaat? Licht je<br />
antwoorden kort toe.<br />
a B b = new B();<br />
int resultaat = b.twintig(2);<br />
b A a = new C();<br />
int resultaat = a.tien(2);<br />
c A a = new C();<br />
int resultaat = a.twintig(2);<br />
d A a = new C();<br />
int resultaat = a.superTien(2);<br />
e B b = new B();<br />
int resultaat = b.superTien(2);<br />
80
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Voorkennis<br />
Taakdoel<br />
Oriëntatie<br />
Verwerking<br />
Verdieping<br />
Zelftoets<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Moduletaak 5 : Collections.<br />
Basiskennis Java uit de modulen IG9 P_J1 IG9 P_J2 en basiskennis informatieanalyse uit IG9<br />
I_A1, IG9 I_A2<br />
Verwerking moduletaken 1 t/m 4<br />
In de module Programmeren in Java 2 heb je kennis gemaakt met het gebruik van een Set, een<br />
dynamische datastructuur. De kennismaking was toen vrij smal, er werd van één soort collectie<br />
kennis gemaakt, terwijl er ook vaak behoefte is aan een collectie met andere eigenschappen. Hier<br />
gaan we in deze moduletaak verder op in.<br />
• Je maakt kennis met diverse standaard collectietypen, waarvan er een aantal te vinden zijn in<br />
de Java Collection Framework (JCF).<br />
• Je leert hoe je een aantal standaard collecties gebruikt. In taak 6 ga je zelf een collectie<br />
implementeren.<br />
• Daarnaast leer je hoe je de implementatie van een collectie scheidt van zijn interface. Dit is<br />
een concept wat de flexibiliteit van je software bevordert.<br />
• Tevens leer je gebruik te maken van de Java 2 API documentatie.<br />
Bestudeer de leestekst Collecties L5.1, L5.2 en L5.4<br />
Maak ter introductie oefening 5.1. Werk vervolgens de oefening Bank (oefening 5.2) op het<br />
systeem uit. Hier ga je de reeds bekende bank met behulp van een Map implementeren (ipv Set).<br />
In overleg met de docent wordt verder een selectie van de oefeningen op het werkcollege<br />
uitgevoerd.<br />
• In L5.5 kun je nog eens nalezen hoe een Map met gelijkheid van objecten omgaat.<br />
• De Java Collections Framework, en met name het sorteren van objecten in een collectie wordt<br />
in L5.3 gesproken. Informatie hierover kun je ook vinden op het net.<br />
• In de Java Tutorial kun je online (of downloaden) een uitgebreide behandeling van de Java<br />
Collections Framework vinden. Deze is uitgebreider dan de genoemde leestekst.<br />
http://java.sun.com/docs/books/tutorial/collections/index.html<br />
• Wat extra informatie is nog te vinden in een reader, ook bij Sun<br />
http://developer.java.sun.com/developer/onlineTraining/collections/Collection.html<br />
• Nieuw is het Hoofdstuk van Core Java 2, volume 2 over Collections:<br />
http://developer.java.sun.com/developer/Books/corejava/index.html<br />
• Tot slot vind je in de paragraaf L5.6 nog wat achtergrondinformatie over de JCF<br />
Maak ter afronding van deze moduletaak de zelftoets en controleer zelf je uitwerkingen met die<br />
in de bijlage van deze modulehandleiding. Herhaal zonodig enkele oefeningen of vraag de<br />
docent om extra oefenmateriaal.<br />
81
LEESTEKST: Collecties<br />
L5.0 Samenvatting<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
• scheiden van implementatie en de interface<br />
• standaard collecties<br />
• Set en Map collecties<br />
• Lijst collecties: Queue, Stack en Sequence<br />
• De ‘primitieve’ array<br />
• Benaderen van een collectie, de Iterator<br />
• Collections in de Java Collection Framework<br />
• Ordening in collecties, de Compatator<br />
• Algoritmen, de Collections class<br />
• oude gedienden, de Vector en Hashtable<br />
• verdieping: optional operations, even opletten<br />
L5.1 Scheiden van implementatie en zijn interface<br />
Als we in een programma kiezen voor een bepaald soort collectie, is het nog niet altijd zeker welke<br />
implementatie het meest geschikt zal zijn. Zo kan het zijn dat het een kleine collectie betreft met<br />
weinig toegang of een uit de kluiten gewassen systeem met capaciteitsproblemen. Om te<br />
vermijden dat men een keuze moet maken waaraan men ‘zijn leven lang’ vastzit, ook na het<br />
ontstaan van andere randvoorwaarden, is het handig om de daadwerkelijke implementatie te<br />
scheiden van zijn interface, ofwel: je legt het type collectie wel vast, dus wat je ermee moet<br />
kunnen, maar hoe het onder water gerealiseerd wordt niet. Welnu, het type collectie kun je<br />
beschrijven middels een interface. Deze geeft aan welke functionaliteit de collectie moet bezitten.<br />
In de implementatie van dit interface, ofwel een class welke de interface implementeert, wordt deze<br />
functionaliteit dan uitgewerkt. Wil je een andere implementatie welke wellicht dan beter past bij je<br />
toepassing, een stukje fine- tuning, dan hoef je alleen bij het creëren van de collectie dit te<br />
veranderen.<br />
Voor de rest blijft het gebruik van de collectie gelijk omdat overal in je programma wordt uitgegaan<br />
van de beschikbare methoden zoals in de interface beschreven.<br />
We hebben dit ook al gezien in de module Programmeren in Java 2. Hier hebben we een<br />
algemene collectie gebruikt met het interace Set, met de implementatie HashSet()<br />
Set boeken = new HashSet();<br />
Je kunt hier een eigen implementatie aan hangen door een kleine wijziging:<br />
Set boeken = new MySet();<br />
Verder hoef je in je programma niets te wijzigen, wat vervelende bugs voorkomt.<br />
Het scheiden van een implementatie en zijn interface wordt ook wel ‘Programming to the interface’<br />
genoemd en wordt o.a. toegepast bij collecties, maar ook bij andere classes waarbij men de<br />
vrijheid van implementatiekeuze wil houden.<br />
82
L5.2 Standaard collectie types<br />
L5.2.1 Set<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Het aantal soorten collecties dat als standaard geld zijn redelijk beperkt. In taak 6 geen we kijken<br />
hoe je tot een keuze van een collectie-type komt. Eerst laten we zien hoe je ze kunt gebruiken. Dit<br />
zal de keuze later vereenvoudigen. Als gemeenschappelijke kenmerk hebben ze dat ze allemaal<br />
een serie elementen beheren. Een deel van de hier genoemde collecties is opgenomen in de Java<br />
Collections Framework (JCF).<br />
Om deze serie elementen te kunnen benaderen is onder andere de iterator een nuttig hulpmiddel.<br />
De iterator stelt ons in staat om in de elementen te ‘bladeren’. Dit is eerder besproken in de module<br />
‘Programmeren in Java 2’ en wordt hier niet verder op ingegaan.<br />
We bekijken hier drie soorten collecties:<br />
• De Set<br />
Een verzameling van objecten, met als bijzonder kenmerk dat elk object maar één keer in de<br />
Set kan voorkomen. De Set is opgenomen in de JCF.<br />
• De Map<br />
Een verzameling key / value combinaties. Ook de map is opgenomen in de JCF.<br />
• De List<br />
Bij een lijst liggen de elementen in een bepaalde volgorde. Dit is niet persé gesorteerd. Er zijn<br />
vele vormen van lijsten te bedenken. De List is als interface opgenomen in de JCF.<br />
• Stack (stapel: last in, first out)<br />
• Queue (wachtrij: first in, first out)<br />
• Sequence of ook de LinkedList. De LinkedList is opgenomen in de JCF<br />
• array: als primitieve- type houdt de array zijn bepaald aantal elementen op volgorde.<br />
Een dynamische variant is de ArrayList, welke opgenomen is in de JCF<br />
De list kent nog uitbreidingen zoals een tree. Dit zijn complexere structuren die in de modulen<br />
verder niet aan de orde komen, maar wel als implementatie in de Java Collections Framework<br />
terug te vinden zijn. (TreeSet en TreeMap).<br />
De functionaliteit van de collecties, behalve van de array, kun je vastleggen in een interface zoals<br />
voor een deel al is gedaan in de Java Collection Framework. Dit betekent dat er per interface<br />
implementaties beschikbaar moeten zijn met allemaal hun eigen specifieke gedrag. Echter, daar<br />
de functionaliteit is vastgelegd in de interface zal vooral de interface besproken worden.<br />
In het navolgende wordt elk type kort belicht. In de bespreking van de Java Collections Framework<br />
(L5.3) wordt het gebruik nader toegelicht.<br />
De Set is eigenlijk de wiskundige vorm van een verzameling. Er kunnen <strong>Object</strong>en geplaatst worden<br />
en weer verwijderd. Tevens kan gekeken worden of een object al in de Set zit. Hiernaast zie je een<br />
eenvoudige interface zoals dat voor een Set kan gelden. Voor<br />
de notatie is UML gebruikt. Deze Set interface is niet die zoals<br />
<br />
Set<br />
in de Java Collection Framework is gedefinieerd, maar bevat<br />
Set<br />
add(element<br />
slechts een subset van de functionaliteit.<br />
add(element : : <strong>Object</strong>) : : void<br />
contains(element : : <strong>Object</strong>) : : boolean<br />
remove(element : : <strong>Object</strong>) : : void<br />
Er geld dat een object maar één keer in een Set mag<br />
isEmpty() : : boolean<br />
voorkomen. Als we dus objecten gaan plaatsen moeten we er size() : : int int<br />
dus zeker zijn dat het obejct niet al geplaatst is, eventueel eerst iterator() : : Iterator<br />
controleren met de methode contains. Voor het bepalen of een<br />
object gelijk is aan een al eerder geplaatst object, wordt in de HashSet implementatie gebruik<br />
gemaakt van een combinatie van de functies hashcode en equals een object. Dus niet op<br />
referentiebasis. Zie hiervoor L5.3. Wil je dus eigen klasses in een Set plaatsen, moet je dus deze<br />
methoden ook implementeren. Een class als de String heeft dit al.<br />
In de JCF kent de Set één implementatie , de HashSet. Deze implementatie gebruikt zg hashing<br />
om de elementen te beheren. Zie ook Computer Science (Brooksheare) L8.4. De Set is<br />
ook een onderdeel van de Java Collections Framework.<br />
83
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een voorbeeld van gebruik van de Set met de implementatie HashSet:<br />
Class SuperMarkt<br />
import java.util.Set;<br />
import java.util.HashSet;<br />
import java.util.Iterator;<br />
public class SuperMarkt {<br />
private String naam;<br />
private Set artikelen = new HashSet();<br />
public SuperMarkt(String deNaam) {<br />
naam = deNaam;<br />
}<br />
// een aantal methoden zijn weggelaten<br />
public void nieuwArtikel(String naam, String code, double prijs) {<br />
// !artikelCodeBestaat<br />
Artikel artikel = new Artikel(naam, code, prijs);<br />
artikelen.add(artikel);<br />
}<br />
public void remove(String code} {<br />
// artikelcode bestaat<br />
Artikel artikel = getArtikel(code);<br />
artikelen.remove(artikel);<br />
}<br />
public void aanvullenVoorraden() {<br />
// codeBestaat == true;<br />
Iterator i = artikelen.iterator();<br />
Artikel artikel;<br />
while (i.hasNext()) {<br />
artikel = (Artikel)i.next();<br />
if (artikel.onderMinimumVoorraad()) {<br />
bestel(artikel);<br />
}<br />
}<br />
}<br />
public boolean codeBestaat(String code) { // controlefunctie voor gui<br />
// code != null<br />
Iterator i = artikelen.iterator();<br />
Artikel artikel;<br />
boolean gevonden = false;<br />
while (i.hasNext() && !gevonden) {<br />
artikel = (Artikel)i.next();<br />
if (code.equals(artikel.getCode())) {<br />
gevonden = true;<br />
}<br />
}<br />
return gevonden;<br />
}<br />
private Artikel getArtikel(String code) {<br />
// codeBestaat == true;<br />
Iterator i = artikelen.iterator();<br />
Artikel artikel = null;<br />
boolean gevonden = false;<br />
while (i.hasNext() && !gevonden) {<br />
artikel = (Artikel)i.next();<br />
if (code.equals(artikel.getCode())) {<br />
gevonden = true;<br />
}<br />
}<br />
return artikel;<br />
}<br />
} // einde class Supermarkt<br />
84
L5.2.2 Map<br />
Map<br />
IG9OGO<br />
Map.Entry<br />
Map.Entry<br />
Map.Entry<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een sleutel is een uniek identificatie/key- object voor een<br />
bepaald value- object zoals bijvoorbeeld het isbn- nummer<br />
voor een boek of een sofinummer van een werknemer. Het<br />
begrip key of sleutel kennen we ook bij databases.<br />
Bij een map wordt gesproken van het plaatsen van een value<br />
onder zijn key. De key wordt ook weer gebruik om het value<br />
bij een bepaalde key weer te benaderen. Dit kan vrij efficient<br />
zijn<br />
Key<br />
Value<br />
Key<br />
Value<br />
Key<br />
Value<br />
Terwijl een key altijd uniek is, kan een value wel onder<br />
meerdere keys in de map staan.<br />
Het object- diagram toont hoe een drietal key/value,<br />
gebundeld in een map-entry, in de map staan. Elke<br />
map entry is uniek omdat elke key/value combinatie<br />
uniek is. De Map is dus een Set van entry’s.<br />
De Map is opgenomen als interface in de JCF en kent<br />
een implementatie HashMap. Onderstaand voorbeeld,<br />
analoog aan het voorbeeld bij de Set laat het gebruik<br />
zien in de Supermarkt.<br />
Interessant is bij de Map het gebruik van de iterator. Daar een Map in principe key/value entrys<br />
bevat, kun je niet rechtstreeks een iterator opvragen. Wel kun je een iterator van de keys of van de<br />
values opvragen door eerst alleen de keys of alleen de values als collectie op te vragen. Daarna<br />
kun je de iterator bemachtigen.<br />
Toevoegen aan een Map gaat als volgt. We gaan uit van een map van boeken<br />
Map boeken = new HashMap();<br />
String isbn = “0-13-766957-7”;<br />
String titel = “Core Java 1.1 Volume 1 <strong>–</strong> Fundamentals”<br />
String schrijver = “Cay S. Horstmann”;<br />
Boek boek = new Boek(isbn, titel, schrijver);<br />
boeken.put(isbn, boek); // gebruik isbn als key voor het boek<br />
Benaderen gaat ook via de key<br />
String isbn = “0-13-766957-7”;<br />
Boek boek = (Boek)boeken.get(isbn);<br />
Verwijderen gaat ook weer met de key. De key mét de value (entry) worden uit de map verwijderd.<br />
String isbn = “0-13-766957-7”;<br />
boeken.remove(isbn);<br />
Controle op aanwezigheid kan voor de key én voor de value<br />
String isbn = “0-13-766957-7”;<br />
Boolean keyAanwezig = boeken.containsKey(isbn);<br />
Boolean valueAanwezig = boeken.containsValue(boek);<br />
Verkrijgen van de iterators<br />
Iterator keysIterator = boeken.keySet().iterator()<br />
Iterator valuesIterator = boeken.values().iterator();<br />
<br />
Map<br />
put(key : : <strong>Object</strong>, value : : <strong>Object</strong>) : : void<br />
containsKey(key : : <strong>Object</strong>) : : boolean<br />
containsValue(value : : <strong>Object</strong>) : : boolean<br />
remove(key : : <strong>Object</strong>) : : void<br />
get(key : : <strong>Object</strong>) : : <strong>Object</strong><br />
isEmpty() : : boolean<br />
size() : : int int<br />
iterator() : : Iterator<br />
85
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een voorbeeld van gebruik van de Map met de implementatie HashMap<br />
Class SuperMarkt<br />
import java.util.Map;<br />
import java.util.HashMap;<br />
import java.util.Iterator;<br />
public class SuperMarkt {<br />
private String naam;<br />
private Map artikelen = new HashMap();<br />
public SuperMarkt(String deNaam) {<br />
naam = deNaam;<br />
}<br />
// een aantal methoden zijn weggelaten<br />
public void nieuwArtikel(String naam, String code, double prijs) {<br />
// !artikelCodeBestaat<br />
Artikel artikel = new Artikel(naam, code, prijs);<br />
artikelen.put(code, artikel); //zet artikel onder code weg<br />
}<br />
public void remove(String code} {<br />
// artikelcode bestaat<br />
artikelen.remove(code);<br />
}<br />
public void verkoop(String code, int aantal) {<br />
// codeBestaat == true<br />
// artikelVoorraad > aantal<br />
Artikel artikel = (Artikel)artikelen.get(code);<br />
artikel.verlaagVoorraad(aantal);<br />
}<br />
public void aanvullenVoorraden() {<br />
Iterator i = artikelen.values().iterator();<br />
Artikel artikel;<br />
while (i.hasNext()) {<br />
artikel = (Artikel)i.next();<br />
if (artikel.onderMinimumVoorraad()) {<br />
bestel(artikel);<br />
}<br />
}<br />
}<br />
public boolean codeBestaat(String code) { // controlefunctie voor gui<br />
// code != null<br />
return artikelen.containsKey(code);<br />
}<br />
private Artikel getArtikel(String code) {<br />
// codeBestaat == true;<br />
return (Artikel)artikelen.get(code);<br />
}<br />
} // einde class Supermarkt<br />
86
L5.2.3 List<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Een List of lijst beheert zijn objecten in een bepaalde volgorde, die, afhankelijk van de<br />
implementatie, te beïnvloeden is. Er is dus sprake van samenhang tussen de objecten.<br />
Vanuit NIAM duiden zinnen als ‘Huis met nummer 14 staat rechts van huis met nummer 16’, of<br />
‘Persoon Jan staat achter Persoon Piet’ op zo’n samenhang.. Dit wordt bij Taak 6 nader belicht.<br />
De volgorde is vaak niet een alfabetische sortering maar een volgorde op andere gronden.<br />
Bijvoorbeeld de huizen staan op nummer (1, 1a, 3, 5, 9, 9a) in de straat en tijdstip van aankomst in<br />
een rij voor de kassa. Taken in een project die achtereenvolgens moeten worden uitgevoerd, of<br />
een stapel kaarten waarbij je slechts vanaf de bovenkant dient te delen. Een adressenlijst ligt<br />
eventueel wel alfabetische volgorde.<br />
Duidelijk niet gesorteerd is een emmer met daarin knikkers, of een oerbos met bomen.<br />
Een lijstimplementatie kan er als volgt uitzien, het betreft hier een een SingleLinkedList ofook een<br />
enkel gelinkte lijst. Kenmerkend zijn de elementen die het te bewaren <strong>Object</strong> kennen maar ook het<br />
volgende element. Op deze manier kun je telkens elementen en objecten toevoegen en zo de lijst<br />
uitbreiden. Je kunt natuurlijk ook elementen (met object) verwijderen. Een Stack zou dit in zijn<br />
implementatie kunnen gebruiken, waarbij de head het bovenste element is.<br />
SingleLinkedList<br />
head<br />
Element<br />
<strong>Object</strong><br />
next next next next<br />
Element Element Element<br />
element element element element element<br />
<strong>Object</strong><br />
<strong>Object</strong> <strong>Object</strong><br />
We kennen dus verschillende lijsten, waarbij het verschil tot uitdrukking komt in de beschikbare<br />
functionaliteit en de daaruit voortvloeiende wijze van onderhouden van de volgorde. We zullen een<br />
paar bekende doornemen….<br />
In L6.3 en L 6.3.1 wordt een implementatie van de List uitgewerkt.<br />
Element<br />
<strong>Object</strong><br />
87
L5.2.3.1 Stack<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De stack is een typisch voorbeeld van een lijst waarbij de<br />
toegang tot de elementen duidelijk beperkt is.<br />
peek() : <strong>Object</strong><br />
Als voorbeeld van gebruik kan dienen een Stapel kratten waarbij<br />
pop() : void<br />
nieuwe kratten steeds bovenop worden geplaatst, het bovenste<br />
isEmpty()<br />
krat als enige toegankelijk is, en ook het bovenste krat als enige<br />
isEmpty() : boolean<br />
size()<br />
te verwijderen is. Door het bovenste krat telkens te verwijderen<br />
size() : int<br />
worden de onderliggen kratten weer toegankelijk.<br />
De Stack geeft een (minimale) interface zoals hiernaast is aangegeven.<br />
De methode push, duwt een object op de stack, terwijl de peek toegang geeft tot het bovenste<br />
element. Met pop kan het bovenste element van de stack afgestoten worden.<br />
Bij een stack spreekt met ook wel van ‘last in, first out’ of lifo.<br />
Een stack wordt ook veel in een computersysteem zelf gebruik, bijvoorbeeld om tussenwaarden<br />
van een berekening te bewaren en door de Java Virtuele Machine om parameters en lokale<br />
variabelen, tijdelijk, te bewaren.<br />
Een voorbeeld van een Stack en zijn implementatie. Overigens maakt deze stack (stapel)<br />
implementatie ‘handig’ gebruik van een al in java beschikbare class LinkedList. Zo kan men<br />
bijvoorbeeld ook een implementatie maken op basis van een Vector (VectorStack) of er voor<br />
kiezen om een geheel eigen implementatie te creëren (MyStack) of een stack die op schijf wordt<br />
bijgehouden (FileStack).<br />
public interface Stack {<br />
public void push(<strong>Object</strong> element);<br />
public void pop();<br />
public <strong>Object</strong> peek();<br />
public boolean isEmpty();<br />
public int size();<br />
}<br />
public class LinkedListStack implements Stack {<br />
private LinkedList elements = new LinkedList();<br />
// zet het object boven op de stapel<br />
public void push(<strong>Object</strong> element) {<br />
elements.addLast(element);<br />
}<br />
//verwijder het bovenste element<br />
public void pop() {<br />
elements.removeLast();<br />
}<br />
// kijk wat er bovenop de stapel ligt<br />
public <strong>Object</strong> peek() {<br />
return elements.getLast();<br />
}<br />
public boolean isEmpty() {<br />
return elements.isEmpty();<br />
}<br />
public int size() {<br />
return elements.size();<br />
}<br />
}<br />
Je kunt je nu afvragen waarom je een ‘wrapper’ om de al<br />
<br />
Stack<br />
push(element : <strong>Object</strong>) : void<br />
<br />
Stack<br />
push(element : <strong>Object</strong>) : void<br />
peek() : <strong>Object</strong><br />
pop() : void<br />
isEmpty() : boolean<br />
size() : int<br />
LinkedListStack<br />
elements : LinkedList<br />
push(element : <strong>Object</strong>) : void<br />
peek() : <strong>Object</strong><br />
pop() : void<br />
isEmpty() : boolean<br />
size() : int<br />
beschikbare LinkedList zou leggen als deze al die functionaliteit al in zich heeft….<br />
Welnu, de LinkedList is een soort manusje van alles. Je kunt er op allerlei manieren de elementen<br />
inzetten en verwijderen. Als uit een analyse volgt dat ik voor mijn toepassing de functionaliteit van<br />
een stack nodig heb, en niet meer dan dat, is een stack de betere keus omdat ik onbedoelde<br />
manipulatie kan voorkomen, en dus foutief gebruik, van de collectie in mijn programma, wat de<br />
robuustheid bevordert.<br />
88
L5.2.3.2 Queue<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Als er in een lijst sprake is dat geld ‘first in, first out’ of fifo (wie het eerst is, het eerst maalt) dan<br />
spreken we van een queue of een wachtrij. Dit kennen we van de rijen voor de kassa of de printopdrachten<br />
die via een netwerk worden uitgevoerd. Bij de queue kunnen aan het eind objecten<br />
worden toegevoegd. Benaderen en weghalen gebeurt aan het begin. Net als bij de stack wordt de<br />
samenhang van de objecten niet door de objecten zelf verzorgd maar door elementen.<br />
Ook de queue kent net als de stack een beperkte functionaliteit, opnieuw om foutief gebruik te<br />
voorkomen. Een voorbeeld van een Queue interface en implementatie staan hieronder. Opnieuw is<br />
er geimplementeerd op basis van een LinkedList<br />
public interface Queue {<br />
public void add(<strong>Object</strong> element);<br />
public <strong>Object</strong> get();<br />
public void remove();<br />
public boolean isEmpty();<br />
public int size();<br />
}<br />
public class LinkedListQueue implements Queue {<br />
private LinkedList elements = new LinkedList();<br />
}<br />
L5.2.3.3 Sequence<br />
// voeg achter aan de Queue toe<br />
public void add(<strong>Object</strong> element) {<br />
elements.addLast(element);<br />
}<br />
// haal het eerste element<br />
public <strong>Object</strong> get() {<br />
return elements.getFirst();<br />
}<br />
// verwijder het eerste element<br />
public void remove() {<br />
elements.removeFirst();<br />
}<br />
public boolean isEmpty() {<br />
return elements.isEmpty();<br />
}<br />
public int size() {<br />
return elements.size();<br />
}<br />
De sequence beheert zijn elementen in een bepaalde volgorde en deze zijn dus alleen in die<br />
volgorde te benaderen. Je kunt dus niet even een element zomaar overslaan. In tegenstelling tot<br />
de stack en queue hoef je hier echter niet een object te<br />
verwijderen om bij de volgende te komen. Je kunt dus<br />
<br />
herhaaldelijk door de sequence lopen zonder deze te<br />
Sequence<br />
veranderen. Overigens wordt ook hier de samenhang tussen add(element : : <strong>Object</strong>) : : void<br />
de objecten verzorgd door elementen (ook wel entry’s).<br />
remove(element : : <strong>Object</strong>) : : void<br />
contains(element : : <strong>Object</strong>) : : void<br />
Het toevoegen van een object geschied ook weer achteraan.<br />
Het verwijderen van een bepaald object is overal mogelijk, dit<br />
in tegenstelling tot het verwijderen bij de stack en queue.<br />
<br />
Queue<br />
add(element : : <strong>Object</strong>) : : void<br />
get() : : <strong>Object</strong><br />
remove() : : void<br />
isEmpty() : : boolean<br />
size() : : int int<br />
iterator() : : Iterator<br />
Overigens zijn er meerdere definities van de sequence mogelijk. Volgens de JCF is de LinkedList<br />
een Sequence. Dit is er dan wel één met heel veel <strong>–</strong>niet sequence- functionaiteit. Wel kun je heel<br />
makkelijk een sequence op basis van een LinkedList implementeren. (zie voorbeelden bij stack en<br />
queue).<br />
Het doorlopen van een sequence geschiedt met een iterator, of ook een ListIterator in de JCF.<br />
89
L5.3 De Java Collections Framework (JCF)<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Nu we een aantal collecties al wat nader hebben bekenen kunnen we eens wat verder kijken naar<br />
de met Java 2 meegeleverde classes en interfaces. De JCF is nadrukkelijk gericht op het scheiden<br />
van implementatie en interface. Het kent dan ook een uitgebreide hierarchie van interfaces, welke<br />
uiteindelijk resulteren in een implementatie. De JCF-classes vindt je in de package java.util.<br />
Onderstaande class diagram laat de structuur van de JCF-interfaces met de bijbehorende<br />
implementaties zien.<br />
<br />
Set<br />
<br />
SortedSet<br />
<br />
Collection<br />
Collections <strong>–</strong> de interfaces<br />
<br />
List<br />
TreeSet HashSet LinkedList ArrayList<br />
<br />
Iterator<br />
<br />
ListIterator<br />
Collections <strong>–</strong> de implementaties<br />
<br />
Map<br />
<br />
SortedMap<br />
HashMap TreeMap<br />
90
L5.3.1 Interface Collection<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
In de Collection interface zijn de gemeenschappelijkheden van<br />
de Set en de List neergelegd. Zo kun je <strong>Object</strong>en toevoegen,<br />
controleren op aanwezigheid, verwijderen, controleren of de<br />
collectie leeg is, de grootte opvragen en doorzoeken met behulp<br />
van een Iterator, zoals we al eerder hebben gezien bij de Set en<br />
de LinkedList.<br />
In nevenstaand diagram zie je dat er heel wat extra functionaliteit<br />
standaard in elke Collection is ingebouwd. Veel hiervan zul je<br />
vooreerst niet of nauwelijk gebruiken. Raadpleeg de JDK 1.2 API<br />
voor gedetailleerde informatie.<br />
L5.3.2 Interface Set<br />
De Set interface van de JCF erft van de Collection interface en is<br />
veel uitgebreider dat de eerder voorgestelde Set. Net zoals van<br />
de collection zul je ook hiervan in eerste instantie het meeste<br />
niet gebruiken.<br />
In de Java 2 API (JavaDoc documentatie) vind je gedetaileerde<br />
informatie bij elke beschikbare methode.<br />
L5.3.3 Interface SortedSet<br />
De Set kent nog een variant, de interface SortedSet. Waar een<br />
Set een ongeordende verzameling van objecten is, bewaart een<br />
SortedSet de objecten volgens een ordening.<br />
Deze ordening kan worden bepaald door de ‘natural ordering’,<br />
ofwel aan de hand van de compareTo methode uit de interface<br />
Comparable of met behulp van een Comparator, met de<br />
methode public int compare (<strong>Object</strong> o1, <strong>Object</strong> o2), een class<br />
welke de interface Comparator implementeert en twee objecten<br />
van het juiste zelfde type met elkaar vergelijkt.<br />
De Comparator biedt hierbij de meeste flexibiliteit, omdat<br />
meerdere comparators bij een object - type kunnen worden gedefinieerd, en verdient daarom<br />
veelal de voorkeur eventueel in combinatie met de ‘natural ordening’.<br />
Comparators kunnen ook voor andere doeleinden worden gebruikt zoals voor de sorteeralgoritmen<br />
in de class Collections uit de java.util package.<br />
De SortedSet heeft extra methoden<br />
beschikbaar, die naast dat ze informatie<br />
geven over de gebruikt ordening, gebruik<br />
maken van de ordening. In de API-<br />
documentatie van de SortedSet kun je dit<br />
nalezen. De ordening van de SortedSet vind<br />
je terug in de volgorde waarop de iterator de<br />
SortedSet doorloopt en de methode toString.<br />
Ook de first en last maken hiervan gebruik.<br />
<br />
Collection<br />
(from<br />
(from<br />
util)<br />
util)<br />
size() : : int int<br />
isEmpty () () : : boolean<br />
contains(o : : <strong>Object</strong>) : : boolean<br />
iterator() : : Iterator<br />
toArray () () : : <strong>Object</strong>[]<br />
toArray (a[] (a[] : : <strong>Object</strong>) : : <strong>Object</strong>[]<br />
add(o : : <strong>Object</strong>) : : boolean<br />
remov e(o e(o : : <strong>Object</strong>) : : boolean<br />
containsAll(c : : Collection) : : boolean<br />
addAll(c : : Collection) : : boolean<br />
remov eAll(c : : Collection) : : boolean<br />
retainAll(c : : Collection) : : boolean<br />
clear() : : v oid oid<br />
equals(o : : <strong>Object</strong>) : : boolean<br />
hashCode() : : int int<br />
<br />
Set Set<br />
(from<br />
(from<br />
util)<br />
util)<br />
size() : : int int<br />
isEmpty () () : : boolean<br />
contains(o : : <strong>Object</strong>) : : boolean<br />
iterator() : : Iterator<br />
toArray () () : : <strong>Object</strong>[]<br />
toArray (a[] (a[] : : <strong>Object</strong>) : : <strong>Object</strong>[]<br />
add(o : : <strong>Object</strong>) : : boolean<br />
remov e(o e(o : : <strong>Object</strong>) : : boolean<br />
containsAll(c : : Collection) : : boolean<br />
addAll(c : : Collection) : : boolean<br />
retainAll(c : : Collection) : : boolean<br />
remov eAll(c : : Collection) : : boolean<br />
clear() : : v oid oid<br />
equals(o : : <strong>Object</strong>) : : boolean<br />
hashCode() : : int int<br />
<br />
SortedSet<br />
(from<br />
(from<br />
util)<br />
util)<br />
comparator() : : Comparator<br />
subSet(f romElement : : <strong>Object</strong>, toElement : : <strong>Object</strong>) : : SortedSet<br />
headSet(toElement : : <strong>Object</strong>) : : SortedSet<br />
tailSet(f romElement : : <strong>Object</strong>) : : SortedSet<br />
ffirst() irst() : : <strong>Object</strong><br />
last() : : <strong>Object</strong><br />
De enige implementatie van een SortedSet in de JCF is de TreeSet. Deze implementatie geeft<br />
invulling aan de door de SortedSet interface voorgeschreven methoden en heeft nog een wat extra<br />
functionaliteit, welke implementatie gebonden is. (Zie volgende voorbeeld)<br />
91
L5.3.4 Interface Comparable, ‘Natural Ordering’<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Het toepassen van de ‘natural order’ vereist dat de objecten die we plaatsen Comparable zijn dus<br />
het type moet het interface Comparable implementeren die de methode public int<br />
compareTo(<strong>Object</strong> o) voorschrijft. De methode geeft uitsluitsel of dit object kleiner, gelijk of groter<br />
dan het opgegeven object is. Het resultaat is een negatief, nul of positief getal. Bij gelijkheid, ofwel<br />
resultaat nul, moet dit overeenstemmen met een true resultaat van de equals methode. De<br />
‘natural ordering’ staat slechts één volgorde toe.<br />
Meer over de Comparable interface is te vinden in moduletaak 4. Ik het navolgende voorbeeld<br />
wordt het Comparable interface ook gebruikt.<br />
L5.3.5 Interface Comparator<br />
Een Comparator is een object van een type dat de interface Comparator implementeert.<br />
Gewoonlijk kunnen we bij het te ordenen object de gewenste Comparator opvragen. Deze levert<br />
telkens een Comparator met een andere compare methode.<br />
Het creëren van een Comparator kan slim worden gedaan met behulp van een zogenaamde<br />
anonymous inner class. Met andere woorden, we declareren een referentie van het type<br />
Comparator, kennen er een object aan toe van het interface - type Comparator, waarbij we ter<br />
plekke de implementatie van de methode compare definiëren.<br />
Dit bespaart het definiëren van extra classes, terwijl er wel class-files gegenereerd worden door de<br />
compiler (Artikel$1.class)) . Vaak is het handig om van een object type zowel zijn ‘natural ordering’<br />
als ook extra Comparators te implementeren.<br />
In het volgende voorbeeld zie je een supermarkt, waar gebruik wordt gemaakt van een SortedSet<br />
om zijn artikelen in te beheren. De code - Comparator kan worden opgevraagd bij het Artikel door<br />
aanroep van de static methode getCodeComparator.<br />
Voorbeeld SortedSet en Comparator<br />
import java.util.SortedSet;<br />
import java.util.TreeSet;<br />
public class Supermarkt {<br />
}<br />
private String naam;<br />
private SortedSet artikelen = new TreeSet(Artikel.getCodeComparator());<br />
// private SortedSet artikelen = new TreeSet(); // natural ordening<br />
public Supermarkt(String deNaam) {<br />
naam = deNaam;<br />
}<br />
public void nieuwArtikel(int code, String naam, double prijs) {<br />
Artikel artikel = new Artikel(code, naam, prijs);<br />
artikelen.add(artikel);<br />
}<br />
public SortedSet getArtikelenMetGrotereCode(Artikel ditArtikel) {<br />
SortedSet gezochteArtikelen = artikelen.tailSet(ditArtikel);<br />
gezochteArtikelen.remove(ditArtikel); // verwijder deze<br />
return gezochteArtikelen;<br />
}<br />
public String toString() {<br />
return "Supermarkt " + naam + "\n" + artikelen;<br />
}<br />
// en nog veel meer methoden………<br />
92
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De Supermarkt maakt gebruik van de Class Artikel, welke ook naast de gebruikte code Comparator<br />
ook een naam- en een prijsComparator levert. Deze laatste twee zijn niet bruikbaar als Comparator<br />
voor de SortedSet, daar in de naam en prijs dubbelingen kunnen voorkomen, wat verlies van<br />
elementen in de Set zou veroorzaken. Je zou ze wel goed kunnen gebruiken in collecties waar wel<br />
dubbelingen mogen voorkomen zoals de List. Ook de diverse algoritmen uit de Collections class<br />
kunnen ervan gebruik maken.<br />
De code-comparator is daarentegen wel uniek en bruikbaar als ordening in de TreeSet. Bij de<br />
prijsComparator is het noodzakelijk om te zien dat de vergelijking opgaat tot op 2 decimalen.<br />
Kleinere verschillen worden door de afronding van de double naar int niet gedetecteerd.<br />
import java.util.Comparator;<br />
public class Artikel implements Comparable{<br />
}<br />
private int code;<br />
private String naam;<br />
private double prijs;<br />
public Artikel(int deCode, String deNaam, double dePrijs) {<br />
code = deCode;<br />
naam = deNaam;<br />
prijs = dePrijs;<br />
}<br />
public int compareTo(<strong>Object</strong> ander<strong>Object</strong>) { // interface Comparable<br />
Artikel anderArtikel = (Artikel)ander<strong>Object</strong>;<br />
return code - anderArtikel.code;<br />
}<br />
public static Comparator getCodeComparator() {<br />
Comparator codeComparator = new Comparator() {<br />
public int compare(<strong>Object</strong> ene<strong>Object</strong>, <strong>Object</strong> andere<strong>Object</strong>) {<br />
Artikel eneArtikel = (Artikel)ene<strong>Object</strong>;<br />
Artikel andereArtikel = (Artikel)andere<strong>Object</strong>;<br />
return eneArtikel.code - andereArtikel.code;<br />
}<br />
};<br />
return codeComparator;<br />
}<br />
public static Comparator getNaamComparator() {<br />
Comparator naamComparator = new Comparator() {<br />
public int compare(<strong>Object</strong> ene<strong>Object</strong>, <strong>Object</strong> andere<strong>Object</strong>) {<br />
Artikel eneArtikel = (Artikel)ene<strong>Object</strong>;<br />
Artikel andereArtikel = (Artikel)andere<strong>Object</strong>;<br />
return eneArtikel.naam.compareTo(andereArtikel.naam);<br />
}<br />
};<br />
return naamComparator;<br />
}<br />
public static Comparator getPrijsComparator() {<br />
return new ArtikelPrijsComparator();<br />
}<br />
public boolean equals(<strong>Object</strong> ander<strong>Object</strong>) {<br />
Artikel anderArtikel = (Artikel)ander<strong>Object</strong>;<br />
return code == anderArtikel.code &&<br />
naam.equals(andereArtikel.naam) &&<br />
prijs == andereArtikel.prijs;<br />
}<br />
public int hashCode() {<br />
return code; //de unieke code volstaat als hashCode<br />
}<br />
public String toString() {<br />
return code + " : " + naam + " voor f " + prijs + "\n";<br />
}<br />
// en nog veel meer methoden………<br />
93
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Het Artikel maakt als voorbeeld gebruik van de externe ArtikelPrijsComparator:<br />
import java.util.Comparator;<br />
public class ArtikelPrijsComparator implements Comparator {<br />
}<br />
public int compare(<strong>Object</strong> ene<strong>Object</strong>, <strong>Object</strong> andere<strong>Object</strong>) {<br />
// pre: ene<strong>Object</strong> instanceof Artikel && andere<strong>Object</strong> instanceof Artikel<br />
Artikel eneArtikel = (Artikel)ene<strong>Object</strong>;<br />
Artikel andereArtikel = (Artikel)andere<strong>Object</strong>;<br />
return (int)((eneArtikel.getPrijs() - andereArtikel.getPrijs())*100);<br />
}<br />
Het verdient aanbeveling om ook bij eigen implementaties waar ordening van objecten een rol<br />
spelen de Comparator interface te gebruiken.<br />
Overigens gaan alle comparators ervan uit dat de opgegeven objecten van het juiste type zijn en<br />
geven een ClassCastException indien dit niet het geval is. Er is hier dus sprake van een niet<br />
afgedwongen, middels asserties, maar wel gedocumenteerde pre-conditie. Zie hiervoor de APIdocumentatie<br />
bij de Comparator.<br />
L5.3.6 Interface Map<br />
De Map kent in de JCF en implementatie HashMap zoals we in L5.2 al hadden gezien, maar ook<br />
een variant, de SortedMap waarbinnen de keys van de map op orde worden gehouden conform<br />
de elementen in een SortedSet. De SortedMap kent een implementatie TreeMap.<br />
L5.3.7 Interface SortedMap<br />
Naast de Map interface is er, in analogie met de Set en SortedSet, de SortedMap welke zijn keys<br />
op orde houdt. Deze ordening wordt bepaald door de ‘natural ordering’ met de Comparable<br />
interface, of de meegegeven Comparator. Het gebruik van de interfaces Comparable en Compare<br />
is precies eender te gebruiken als bij de SortedSet.<br />
L5.3.8 Interface List<br />
Een (JCF)list bewaard zijn elementen in een vaste<br />
volgorde. Op een bepaalde plaats, aangeduid met een<br />
index, kun je elementen benaderen, tussenvoegen en<br />
verwijderen. Een volgorde wil zeker niet zeggen dat er<br />
sprake is van ordening. De volgorde van de elementen is<br />
volkomen afhankelijk door de wijze en volgorde van<br />
toevoegen en verwijderen. Een List kent dan ook geen<br />
sorted variant zoals de Set en Map.<br />
De (JCF)list lijkt qua omgang veel op een primitieve array<br />
omdat hij werkt met een index, maar dan wel een<br />
dynamische variant. Een kijkje in de source van de Listimplementatie<br />
ArrayList leert dat deze inderdaad is<br />
gebaseerd op een array van <strong>Object</strong>en. Dit maakt dat deze<br />
implementatie vaak snel is, maar duur als het op het<br />
verwijderen van objecten, of juist het tussenvoegen ervan<br />
aankomt. Dan moet namelijk de array wordt opgeschoven<br />
om plaats te maken of een ontstaan gat te vullen.<br />
De LinkedList implementatie vanuit de object orientatie<br />
gezien een fraaier oplossing met Entry’s (inner class van<br />
LinkedList) welke de objecten bewaren, en verwijzen naar<br />
de vorige en volgende Entry.<br />
Dit komt overeen met de wijze waarop we in Moduletaak 6<br />
een eigen List variant gaan maken. Dit betreft dan<br />
bijvoorbeeld een Queue, Stack, een .Sequence of een<br />
Circular- List.<br />
<br />
List List<br />
(from<br />
(from<br />
util)<br />
util)<br />
size() : : int int<br />
isEmpty () () : : boolean<br />
contains(o : : <strong>Object</strong>) : : boolean<br />
iterator() : : Iterator<br />
toArray () () : : <strong>Object</strong>[]<br />
toArray (a[] (a[] : : <strong>Object</strong>) : : <strong>Object</strong>[]<br />
add(o : : <strong>Object</strong>) : : boolean<br />
remov e(o e(o : : <strong>Object</strong>) : : boolean<br />
containsAll(c : : Collection) : : boolean<br />
addAll(c : : Collection) : : boolean<br />
addAll(index : : int, int, c : : Collection) : : boolean<br />
remov eAll(c : : Collection) : : boolean<br />
retainAll(c : : Collection) : : boolean<br />
clear() : : v oid oid<br />
equals(o : : <strong>Object</strong>) : : boolean<br />
hashCode() : : int int<br />
get(index : : int) int) : : <strong>Object</strong><br />
set(index : : int, int, element : : <strong>Object</strong>) : : <strong>Object</strong><br />
add(index : : int, int, element : : <strong>Object</strong>) : : v oid oid<br />
remov e(index : : int) int) : : <strong>Object</strong><br />
indexOf (o (o : : <strong>Object</strong>) : : int int<br />
lastIndexOf (o (o : : <strong>Object</strong>) : : int int<br />
listIterator() : : ListIterator<br />
listIterator(index : : int) int) : : ListIterator<br />
subList(f romIndex : : int, int, toIndex : : int) int) : : List<br />
List<br />
94
L5.3.9 De Collections class<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
Buiten de leerstof van deze module taak valt de Collections class met zijn algoritmen voor gebruik<br />
met de diverse collecties. Je vind deze class ook in de java.util package. Nadere informatie kun je<br />
vinden in de java 2 - api-documentatie .<br />
L5.3.10 Legacy, Vector & Hashtable<br />
De Java Collections Framework was onder eerdere versies van java, dat wil zeggen vóór het<br />
verschijnen van het Java Platform 2 (of ook jdk1.2) niet beschikbaar, tenzij men zelf de collectionpackage<br />
aan de 1.1 packages had toegevoegd.<br />
De plaats voor de import van deze extra collections- package was een andere dan de huidige, de<br />
java.utils- package. Dit levert nu nog soms problemen op.<br />
In java 1.0 en 1.1 was standaard uiteraard de array als primitieve- niet OO- oplossing beschikbaar,<br />
maar ook de Vector (List) en de HashTable (Map).<br />
De Vector komt qua functionaliteit overeen met de ArrayList en wordt vaak gebruikt als een<br />
manusje van alles (tricky), terwijl de Hashtable te herkennen is in de HaskMap.<br />
Orgineel waren bij deze classes de implementatie niet gescheiden van de interface, het principe<br />
waarop in de JCF zwaar wordt geleund. Met ingang van java 2, hebben de Vector en Hashtable<br />
een opwaardering gekregen door ze de nodige interfaces te laten implementeren. De Vector<br />
implementeert de List en de Hashtable de Map.<br />
Deze aanpassing is een tegemoetkoming aan oude java versies, maar moet worden gezien als<br />
verouderd. Ze staan echter (nog) niet als depricated aangemerkt. Desondanks is het over het<br />
algemeen wenselijk om de universelere ‘nieuwe’ JCF-structuur te gebruiken.<br />
95
L5.4 De juiste collectie kiezen<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
We hebben een aantal collectievormen gezien en er ontstaan nu diverse keuzemogelijkheden.<br />
Welke nu te kiezen is afhankelijk van het resultaat van je analyse. In principe kies je allereerst voor<br />
het meest geschikte interface op basis van de typische eigenschappen, welke volgen uit een<br />
analyse.<br />
Daarna kies je pas de feitelijke implementatie op basis van efficiëntie. Zo is het van belang of een<br />
applicatie hebt die vaak wijzigingen aanbrengt in de collectie of juist relatief vaak in de collectie<br />
zoekt.<br />
Een paar hints:<br />
• Is er geen sprake van specifieke eigenschappen, maar slechts een serie objecten, dan voldoen<br />
de Collection met implementatie HashSet, mits er geen dubbelingen voorkomen. Is dit wel het<br />
geval, kies dan een ArrayList. Wordt er veel tussengevoegd en verwijderd dan verdient de<br />
LnikedList de voorkeur boven de ArrayList.<br />
• Mogen er duidelijk geen dubbelingen voorkomen, neem dan de Set met als implementatie de<br />
HashSet.<br />
• Is er duidelijk sprake van een volgorde of rij door een feittype als ‘na Persoon volgt<br />
Persoon ’, dan is een List, met implementatie ArrayList vaak een juiste keuze. Wordt er<br />
veel tussengevoegd en verwijderd dan verdient de LnikedList de voorkeur boven de ArrayList.<br />
• Als er een unieke key te vinden is bij het te beheren object-type dan ligt de keuze voor een<br />
Map voor de hand. Dit bied snelle toegang tot de values.<br />
• Sorteren helpt vaak bij het snel opzoeken van gegevens, maar kosten extra tijd bij wijzigingen.<br />
Je hebt de keuze tussen SortedSet en SortedMap. Een SortedList bestaat niet (waarom ?)<br />
Tabel 1, Implementaies van de diverse interfaces in de JCF<br />
Interfaces<br />
Implementaties<br />
HashTable Resizable array Balanced Tree LinkedList<br />
Set HashSet TreeSet<br />
List ArrayList LinkedList<br />
Map HashMap TreeMap<br />
Als er geen passende collection te vinden is, dan kun je natuurlijk je eigen variant schrijven, al dan<br />
niet gebaseerd op de beschikbare abstracte classes van de JCF. Voor elk van de interface<br />
Collection, Set, List en Map is er minimaal één beschikbaar. Bestudeer hiertoe de APIdocumentatie.<br />
Het verdient altijd de voorkeur om ook voor je eigen implementaties gebruik te maken van een<br />
interface, één van de beschikbare of een nieuw gedefinieerde.<br />
96
L5.5 Gelijkheid van objecten<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> georienteerd <strong>ontwerpen</strong><br />
De HashSet staat slechts één keer hetzelfde object toe, het is tenslotte een verzameling. Alleen<br />
wanneer is nu een object gelijk aan een ander. Als het echt hetzelfde object is, of als de inhoud<br />
gelijk is.<br />
We kunnen zelf bepalen of het ene <strong>Object</strong> inhoudelijk gelijk is aan het andere door zelf de nodige<br />
functionaliteit aan te leveren in de class.<br />
De HashSet bepaald namelijk aan de hand van de hashcode van het object , welke op te vragen is<br />
met de methode int hashCode(), en daarna door aanroep van de methode boolean<br />
equals(<strong>Object</strong>), of een object gelijk is..<br />
Als we dus zelf in onze classes de gelijkheid voor onder andere de HashSet willen aangeven,<br />
moeten we hier dus een eigen hashCode en equals methoden implementeren. In de o.a. de String<br />
is dit dit toegepast. Vandaar dat we ook maar één keer een String met dezelfde inhoud in de<br />
HashSet kunnen plaatsen.<br />
De hashcode is een integer representatie van het object, wat niet uniek hoeft te zijn. Dit is<br />
standaard het referentie adres, maar bij een String is deze bijvoorbeeld afgeleid van de inhoud<br />
(characters). Als we bijvoorbeeld bij de Lezer van de Bieb een int lezersnummer kennen kan dit<br />
een prima hashCode leveren. De hashcode hoeft niet uniek te zijn, maar bijvoorbeeld voor de<br />
HashSet, slechts een grove selectie te vormen voordat de duurdere equals zijn werk kan doen.<br />
De methode equals bepaald of een object op inhoud gelijk wordt beschouwd in plaats van de<br />
referentie vergelijking (ene<strong>Object</strong> == andere<strong>Object</strong> wordt ene<strong>Object</strong>.equals(andere<strong>Object</strong>)).<br />
Het volgende voorbeeld bevat methoden voor een class Adres. Als zowel de hashCode gelijk is en<br />
de equals geeft true gaat de HastSet ervan uit dat de objecten gelijk zijn. Dit is van belang bij o.a.<br />
de methode contains maar ook add en remove. Implementeren we deze methoden niet, dan is elk<br />
object voor de HashSet verschillend.<br />
public class Adres {<br />
private String postCode;<br />
private String straat;<br />
private String huisNummer;<br />
private String woonPlaats;<br />
}<br />
// bevat diversen methoden<br />
public int hashCode() {<br />
return postCode.hashCode(); // gebruik de hashCode van de postCode<br />
}<br />
public boolean equals(<strong>Object</strong> object) {<br />
boolean gelijk = false;<br />
if (object instanceof Adres) { // juiste type ?<br />
Adres adres = (Adres)object; // casten neer juiste type<br />
gelijk = postCode.equals(object.postCode) &&<br />
huisNummer.equals(object.huisNummer);<br />
}<br />
return gelijk;<br />
}<br />
Het is van belang de gelijkheid van objecten goed te documenteren om fouten te voorkomen, zoals<br />
onbedoeld verdwijnen van objecten.<br />
97
L5.6 Optional operations<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
De Java Collection Framework kent zogenaamde optional operations. Dit wil zeggen dat nog<br />
steeds verplicht is om deze methoden in een implementatie op te nemen, maar men het kan<br />
verkiezen niet meer te doen dan het ‘at runtime’ opwerpen van een<br />
UnsupportedOperationException. De java-compiler detecteert overigens de onterechte aanroep<br />
van een unsupported operation niet.<br />
Wil men gebruik maken van zo’n operatie in een collectie, dan dient met vooraf zich te vergewissen<br />
dat deze operaties ook daadwerkelijk ‘supported’ zijn. Eventueel zal men de aanroep van zo’n<br />
optional methode moeten vatten in een ‘try en catch’ blok. Dit vereist dus een bewust gebruik van<br />
bepaalde methoden en dat zal goed gedocumenteerd moeten worden. Men kan dus niet<br />
zondermeer tegen de gekozen interface aan programmeren.<br />
Anderzijds is zeker ook nuttig om, voor zover mogelijk, bij implementatie alle door het interface<br />
vereiste methoden volledig te implementeren, teneinde vreemde, buggie constructies te vermijden.<br />
De standaard collection implementaties maken wel van deze optional opraties gebruik,<br />
bijvoorbeeld bij de HashSet de methoden addAll en RemoveAll.<br />
Deze optionele operaties zijn geïntroduceerd om het Framework eenvoudig te houden en niet voor<br />
elke variant een interface te hoeven definiëren. Hierbij kun je denken aan read- only (immutable of<br />
unmodifiable) collections waarbij bijvoorbeeld de add en de remove geen uitwerking dienen te<br />
hebben. De in de JCF gekozen oplossing is enigszins omstreden.<br />
Praktisch gezien is er best wel mee te leven, mits men zich goed realiseert wat wel en niet te<br />
gebruiken.<br />
98
OEFENINGEN moduletaak 5<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Oefening 5.1:<br />
Kies uit de volgende datastructuren de best passendevoor elk van de genoemde toepassingen.<br />
Data structuren waaruit gekozen kan worden : Set, Map, Array, Queue, Sequence, Stack.<br />
1. Een parkeerterrein met honderd plaatsen en opeenvolgende nummers.<br />
2. Werkplaatshandboek waarin achtereenvolgens te verrichten handelingen staan.<br />
3. Kratten worden op elkaar gezet. Om bijvoorbeeld het onderste krat te bereiken moet men de<br />
kratten er één voor één afhalen.<br />
4. Adressenboek waarin aan de hand van postcode en huisnummer, een naam en adres<br />
worden gevonden<br />
5. Een dienstverlenend bedrijf krijgt storingsmeldingen binnen welke op volgorde van<br />
binnenkomst worden afgehandeld.<br />
6. Een aantal achter elkaar staande mensen voor het loket van een stadion.<br />
7. Een eindige geschakelde ketting , welke aan één zijde bevestigd is.<br />
8. Een telefoonboek (voor één plaats).<br />
9. Een emmer met loten waaruit het winnende lot kan worden gevist.<br />
10. Een lijst met spelers van een voetbalelftal, waarbij voor elk van de 25 rugnummers de speler,<br />
of juist geen speler , wordt genoemd.<br />
Oefening 5.2:<br />
Herschrijf de oefening Bank van het tweede Java Module, maar nu gebruik makend van één Map.<br />
Bedenkt dat een Map eigenlijk twee collecties bevat, Eén van de keys en één van de values<br />
Het betreft die bank met een verzameling rekeninghouders met rekeningen. Een rekeninghouder<br />
kan slechts één rekening hebben. Bedenk de methoden maakRekening, maakRekeninghouder,<br />
KoppelRekeningAanHouder.<br />
• Tot welke verplichtingen leidt het gebruik van de Map hier ?<br />
• Welke problemen kom je tegen.<br />
• Hoe zou je de Bank realiseren met meer Map’s (2 of 3)<br />
Oefening 5.3:<br />
Schrijf zelf een Sequence implementatie op de manier zoals dit ook voor de stack en de queue in<br />
de voolbeelden was gedaan, op basis van een LinkedList. Schrijf ook een eenvoudige test.<br />
99
ZELFTOETS moduletaak 5<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Geef antwoord op de volgende vragen<br />
1. Wat is het verschil tussen een Set en een Map<br />
2. Waartoe dient een interface in de Jaca Collections Classes<br />
3. Welke collection interface kies in als ik studenten met studentnummer wil gaan registreren.<br />
4. Hoe kan ik in een collectie door de elementen zoeken (bijvoorbeeld een Set of een LinkedList).<br />
5. Waarom kan ik bij een map niet direct een iterator opvragen<br />
6. Welke collectie interface en/of implementatie schiet je te binnen bij een parkeerplaats met<br />
genummerde plaatsen.<br />
7. Hoe verwijder in een object uit een Set<br />
8. Hoe gaat een en ander in het werk als ik een object ‘uit’ een Map haal.<br />
9. Waarom zou ik er voor kiezen om een wrapper rond een bestaande implementatie te maken<br />
met een functionele beperktere interface in plaats van de beschikbare interfaces (zoals List).<br />
100
INTRODUCTIE en TAAKOMSCHRIJVING<br />
Voorkennis<br />
Taakdoel<br />
Oriëntatie<br />
Verwerking<br />
Verdieping<br />
Zelftoets<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Moduletaak 6: Ontwerpen van collections<br />
Basiskennis Java uit de modulen IG9_PJ1 IG9P_J2 en basiskennis informatieanalyse uit<br />
IG9_IA1, IG9_IA2<br />
Verwerking moduletaken 1 t/m 4<br />
• De student kan vanuit de analyse standaard datastructuren herkennen.<br />
• De student is in staat om zelf een implementatie van een datastructuur mbv een gelinkte lijst te<br />
maken<br />
In het voorgaande hebben we gezien wat er beschikbaar is aan collections. We moeten echter<br />
vanuit onze NIAM- analyse in staat zijn te oordelen over welk collectie <strong>–</strong> interface, bijvoorbeeld uit<br />
de Java Colections Framework, het beste past. Vaak is het herkennen een structuur in delen in het<br />
IGD voldoende om tot een keuze te komen.<br />
Bestudeer daartoe de navolgende leestekst Ontwerpen van collections L6.0 t/m L6.3.1<br />
Om dieper in de structuur van een collection te duiken implementeren we zelf ‘from scratch’ zelf<br />
een collectie.<br />
Werk daartoe oefening 6.3 uit achter het systeem.<br />
Verder wordt een selectie van de oefeningen op het werkcollege uitgevoerd.<br />
Om nog wat vertrouwder te raken met het implementeren van gelinkte lijsten, kun je de<br />
bovengenoemde opdracht ook uitvoeren met behulp van een LinkedList.<br />
Daarnaast is het bestuderen van de API-documentatie en Java Tutorial bij Javasoft aan te raden.<br />
Eventueel kun je eens een kijkje werpen in de sources van de java- classes.<br />
Maak ter afronding van deze moduletaak de zelftoets en controleer zelf je uitwerkingen met<br />
die in de bijlage van deze modulehandleiding. Herhaal zonodig enkele oefeningen of vraag de<br />
docent om extra oefenmateriaal.<br />
101
L6.0 Samenvatting<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
LEESTEKST bij moduletaak 6 : Ontwerpen van collections<br />
• Analyse leidend tot keuze van een Set<br />
• Analyse leidend tot keuze van een Map<br />
• Analyse leidend tot de keuze van een Stack<br />
• Analyse leidend tot de keuze van een Queue<br />
• Analyse leidend tot de keuze van een Sequence<br />
• Analyse en implementatie van een Stack<br />
• Analyse en implementatie van een LinkedList<br />
L6.1 Afleidingen uit de NIAM analyse<br />
Vanuit het NIAM <strong>–</strong>IGD kun je diverse typen van collecties herkennen. In het navolgende geven we<br />
een aantal voorbeelden die leiden tot een bepaalde keuze.<br />
L6.1.1 Analyse leidend tot de keuze van een Set<br />
In NIAM is elk object uniek, twee keer hetzelfde object komt niet voor. Dit betekent dat vanuit NIAM<br />
elke n op n relatie, met 2 deelnemende object- typen in principe leidt tot het gebruik van een Set.<br />
• Één op meer relatie<br />
A B<br />
A B<br />
dit leidt tot een Set van Bees in A, en één A in B<br />
• meer-op-meer relatie<br />
A B<br />
A B<br />
dit leidt tot een Set van Bees in A, en een Set van Aas in B<br />
Keuze voor een andere collectie- vorm kan op basis van gewenst gedrag wat niet direct volgt uit de<br />
NIAM analyse.<br />
• Indien de volgorde van de elementen van belang is kan worden gekozen voor een List variant<br />
• Als er van het object- type een unieke identificator beschikbaar is, is het vaak handig om deze<br />
te kiezen als key voor een Map.<br />
Als het om een of andere reden nodig of gunstig is om de elementen gesorteerd te houden is een<br />
SortedSet de aangewezen keuze.<br />
102
L6.1.2 Analyse leidend tot de keuze van een Map .<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
De keuze van een Map volgt meestal uit het gebruik van een collection met random access.<br />
Voorwaarde is dat er een identificerende (unieke) key beschikbaar is.<br />
Soms volgt een Map direct uit de analyse:<br />
Bank Rekening<br />
In afwijking van de standaard regels voor ternaire feittypen (nominaliseren) kan dit voorbeeld leiden<br />
tot een Map met rekeningen met key/value is Persoon/Rekening bij een Bank, maar ook tot een<br />
Map met personen met key/value is Rekening/Persoon. Let hierbij op de uniciteiten.<br />
Een schema dat tot een zelfde structuur met een Map kan leiden:<br />
Bank<br />
B<br />
Persoon<br />
P<br />
R<br />
Bij heeft de <br />
Rekeninghouder<br />
B<br />
R<br />
Persoon<br />
is bij rekeninghouder<br />
Rekening<br />
Ondanks de aangegeven nominalisatie in bovenstaand IGD, welke gewoonlijk tot een aparte class<br />
leidt, kun je hier ook gebruik maken van een Map:<br />
• Bank heeft onder sleutel Persoon een Rekening<br />
• Persoon heeft onder sleutel Bank een Rekening<br />
In het algemeen zul je het gebruik, voor zover niet direct uit het IGD af te leiden, moeten kiezen<br />
aan de hand van het gebruik van de collectie. Vaak is het voorhanden zijn van een identificerende<br />
key een hint.<br />
Voorbeelden:<br />
• Unieke naam bij een persoon<br />
• Klantcode bij een bank<br />
• Isbn nummer van een boek<br />
• Streepjescode van een artikel<br />
• Wegnummer van de auto(snel)weg<br />
• Postcode met huisnummer bij de post (benodigd daarvoor een extra key-class)<br />
Implementatie van de Map interface in de JCF is o.a. de HashMap. Zijn voorganger, de Hashtable<br />
is intussen (JDK 1.2) ook voorzien van de Map interface.<br />
Rh<br />
P<br />
heeft <br />
103
L6.1.3 Analyse leidend tot keuze van een Stack<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Alle IGD’s voor collectie met een volgorde (Sequence, Stack, Queue en List ) hebben een<br />
vergelijkbaar schema.<br />
Onderstaand schema leidt op basis van het feittype “ ligt bovenop ” tot de keuze van<br />
een stack<br />
Pallet Krat<br />
Eigenaar<br />
P K<br />
Op staat <br />
Het verschil in keuze tussen een Sequence, Stack, Queue of List zit hem vooral in de verwoording<br />
van de feittypen.<br />
Typisch voor een Stack zijn verwoordingen als<br />
• “staat bovenop”<br />
• “heeft als bovenste”<br />
K1 K2<br />
ligt bovenop <br />
K E<br />
is eigendom van <br />
K I<br />
bevat <br />
Inhoud<br />
104
L6.1.4 Analyse leidend tot de keuze van een queue<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Onderstaand schema leidt tot de keuze van een queue<br />
Kassa Klant<br />
Artikelen<br />
A K<br />
staat vooraan bij <br />
A K<br />
staat achteraan bij <br />
K1 K2<br />
K A<br />
heeft <br />
staat voor <br />
Opnieuw is de verwoording van het feittype hier van belang. Typisch voor een Queue zijn<br />
verwoordingen als<br />
• “staat vooraan” of<br />
• “staat achteraan”<br />
• “staat achter”<br />
De uiteindelijke keuze hangt af van wat met de collection gedaan wordt:<br />
• waar moet een nieuw object worden toegevoegd?<br />
• hoe moet de collection doorlopen kunnen worden?<br />
• etc.<br />
105
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
L6.1.5 Analyse leidend tot de keuze van een Sequence .<br />
Als uit de analyse een bepaalde volgorde tussen de elementen volgt, zoals in onderstaand<br />
voorbeeld zal de keuze van een lijst-vorm volgen. Dat kan dus zijn een Stack, Queue, Sequence of<br />
een List uit de JCF. Welke keuze je maakt is afhankelijk van de vereiste functionaliteit.<br />
Voorbeeld voor keuze van een Sequence<br />
Of<br />
Filmrol Foto<br />
Nummer<br />
R F<br />
bevat <br />
F N<br />
volgt op <br />
Foto<br />
Herkenningspunten voor de Sequence zijn<br />
• het feittype “ volgt op ”<br />
• de een-op-een relatie tussen elkaar opvolgende foto’s<br />
Voorgaande leidt tot de volgende implementatiekeuzes<br />
• In Filmrolletje een Sequence van foto’s<br />
• In Foto een nummer en een Onderwerp<br />
F N<br />
heeft <br />
F O<br />
betreft <br />
Onderwerp<br />
FolmRolletje Nummer<br />
R N<br />
Op staat foto met <br />
F1 F2<br />
komt na<br />
F O<br />
betreft <br />
Onderwerp<br />
Dit betekent dat de volgorde van de foto’s niet gehandhaafd blijft door de foto’s zelf maar deze taak<br />
wordt overgelaten (gedelegeerd) aan de Sequence. De feittypen “ volgt op ” en “<br />
heeft als eerste ” vind je dus niet terug in de de fabeelding van een Foto- class !<br />
Je maakt dus nooit een Foto met een referentie naar een volgende foto, of een boek dat verwijst<br />
naar een volgend boek.<br />
106
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
In het volgende geval kan eveneens tot gebruik van een Sequence worden besloten:<br />
Boekenplank Boek<br />
Auteur<br />
P B<br />
Op staat <br />
B1 B2<br />
staat naast <br />
• In Boekenplank leidt dit tot een Sequence van boeken<br />
• In Boek een Auteur en een Onderwerp<br />
B A<br />
En dan niet bij Boek opnemen : “volgend boek” of “vorig boek” !<br />
Dit zou slecht (en dus FOUT) ontwerp zijn.<br />
is geschreven door <br />
B O<br />
betreft <br />
Onderwerp<br />
De List interface van de JCF lijkt veel op een Sequence, echter een echte sequence heeft een veel<br />
beperktere interface, wat robuustheid kan bevorderen.<br />
107
L6.2 Implementatie van een stack<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
De in taak 5 getoonde implementatie van een stack was gebaseerd op de LinkedList. Het vormde<br />
een wrapper om deze beschikbare implementatie. Dit is handig maar verschaft niet veel inzicht in<br />
de werking van een LinkedList. In deze paragraaf gaan we een Stack implementatie ‘from scratch’<br />
opzetten.<br />
We beginnen met een voorbeeld van een toepassing van de stack. In dit voorbeeld wordt de stack<br />
gebruikt voor het opslaan van tussenwaarden bij een berekening.<br />
Rekenmachine die RPN gebruikt.<br />
RPN: Reverse Polish Notation: Manier van opschrijven van rekenkundige bewerkingen zonder<br />
haakjes<br />
Voorbeeld: (3 + (5 + 8)) * (2 + 4) wordt geschreven als: 3 5 8 + + 2 4 + *<br />
De bewerking wordt uitgevoerd met een stack:<br />
enter<br />
3<br />
In diverse gevallen in de informatica worden stacks gebruikt.<br />
Bijvoorbeeld bij het onthouden van de toestand van een proces, die weer een ander proces kan<br />
aanroepen.<br />
L6.2.1 De werking van de stack<br />
3<br />
enter<br />
5<br />
5<br />
3<br />
enter<br />
8<br />
8<br />
5<br />
3<br />
+<br />
13<br />
3<br />
+<br />
16<br />
enter<br />
2<br />
Bij een stack worden de objecten aan de bovenkant toegevoegd (push) en daar ook er weer<br />
afgehaald (pop). Tevens kan het bovenste object worden benaderd (peek). Let wel, dit is zoals de<br />
stack lijkt te werken. Na analyse weten we we pas hoe hij intern is georganiseerd.<br />
Stack<br />
Stack<br />
bovenste<br />
<strong>Object</strong><br />
<strong>Object</strong><br />
<strong>Object</strong><br />
Werking van put en remove op een<br />
stack<br />
bovenste<br />
<strong>Object</strong><br />
<strong>Object</strong><br />
<strong>Object</strong><br />
<strong>Object</strong><br />
2<br />
16<br />
Start Na toevoegen van een object<br />
(push)<br />
enter<br />
4<br />
4<br />
2<br />
16<br />
+<br />
6<br />
16<br />
Stack<br />
bovenste<br />
*<br />
96<br />
<strong>Object</strong><br />
<strong>Object</strong><br />
<strong>Object</strong><br />
Na verwijderen van een object<br />
(pop)<br />
108
L6.2.2 Analyse van de Stack<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Ten einde een ontwerp te kunnen maken voor een (generieke) stack, analyseren we eerst de stack<br />
mbv NIAM. Het resultaat geven we weer in een IGD<br />
De volgende schets levert ons de nodige voorbeelden. Let op, de elementen van de stack bevatten<br />
de objecten (getallen) en zijn wel genummerd maar liggen niet op die volgorde.<br />
De nummering naast de elementen is voor de identificatie van de elementen. De getallen in de<br />
elementen staan voor het object. Ons voorbeeld kent twee stacks.<br />
S2<br />
5<br />
3<br />
Als we dit voorbeeld analyseren kan het volgend IGD het produkt zijn.<br />
Stack<br />
has as<br />
topmost <br />
S2<br />
S3<br />
S E<br />
2 of S2<br />
2 of S3<br />
2<br />
1<br />
Element<br />
S3<br />
of Number<br />
S N<br />
has an element with <br />
S2<br />
S2<br />
S3<br />
1<br />
2<br />
1<br />
E1 E2<br />
is on<br />
top of <br />
2 of S2 1 of S2<br />
1 of S3 3 of S3<br />
2 of S3 1 of S3<br />
8<br />
5<br />
3<br />
E<br />
2<br />
1<br />
3<br />
O<br />
8<br />
5<br />
3<br />
<strong>Object</strong><br />
contains <br />
2 of S3<br />
1 of S3<br />
3 of S3<br />
109
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Omzetting van het IGD naar classes en attributen levert het volgende op.<br />
• Class Stack<br />
• Set elements<br />
• Element topElement<br />
• Class Element<br />
• Stack hoortByStack<br />
• Stack topOfStack (alleen als hij topelement is)<br />
• Element elementBelow<br />
• Element elementAbove<br />
• <strong>Object</strong> object<br />
• Number number<br />
• Class Number…….<br />
• Class <strong>Object</strong>……. (de te plaatsen objecten)<br />
We kunnen dit nog vereenvoudigen:<br />
• Het object is een Java-<strong>Object</strong>, voor de op de stack te plaatsen objecten<br />
• Nummer kan vervallen (object referentie van een Element maakt hem al uniek)<br />
• De stack hoeft alleen het bovenste element te kennen. De rest ligt daaronder.<br />
• Een Element hoeft niets te weten van de class Stack<br />
• Een element hoeft niet te weten welk element boven hem ligt<br />
• Een object weet niets van de stack (Java- <strong>Object</strong>)<br />
Er blijft dan over:<br />
• Class Stack<br />
• Element topElement<br />
• Class Element<br />
• Element elementBelow<br />
• <strong>Object</strong> object<br />
Zie ook nevenstaand class diagram<br />
topElement<br />
Stack Element<br />
object<br />
<strong>Object</strong><br />
elementBelow<br />
Een object diagram, na respectievelijke toevoeging van de objecten Mies, Noot en Aap ziet er dan<br />
als volgt uit.<br />
Stack<br />
topElement<br />
elementBelow<br />
elementBelow<br />
Element<br />
Element<br />
Element<br />
object<br />
object<br />
object<br />
<strong>Object</strong><br />
Aap<br />
<strong>Object</strong><br />
Noot<br />
<strong>Object</strong><br />
Mies<br />
110
L6.2.3 Implementatie van de classes<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Nu weten we nagenoeg alles wat we nodig hebben om te gaan implementeren. In Taak 5 is<br />
gesteld dat het voor de flexibiliteit handig is om een interface te maken, waarvoor we de<br />
implementatie maken. Dit is dus een extra ontwerpstap, welke je zichtbaar maakt in het class-<br />
diagram.. We maken dus een interface Stack, met een implementatie LinkedListStack (hadden we<br />
die niet al in taak 5 gezien ?)<br />
Het class diagram ziet er dan als volgt uit:<br />
<br />
Stack<br />
push(object : <strong>Object</strong>) : void<br />
peek() : <strong>Object</strong><br />
pop() : void<br />
LinkedListStack<br />
push(object : <strong>Object</strong>) : void<br />
peek() : <strong>Object</strong><br />
pop() : void<br />
topElement<br />
De methoden push en pop zijn mogelijk wat lastig te doorzien. De volgorde van handelen is<br />
kritisch, je raakt je hele stack kwijt als het niet klopt.<br />
1. Eerst de oude stack veilig stellen in het nieuwe element<br />
2. Daarna pas het topelement op het nieuwe<br />
public void push(<strong>Object</strong> object) {<br />
Element element = new Element(); // een element om het object te beheren<br />
element.setElementBelow(topElement); // dit element krijgt de huisige<br />
// bovenste als onderliggende<br />
element.set<strong>Object</strong>(object); // plaats het object in dit element<br />
topElement = element; // nieuwe element is nu bovenste<br />
}<br />
public <strong>Object</strong> peek() {<br />
return topElement.get<strong>Object</strong>();<br />
}<br />
Element<br />
get<strong>Object</strong>() : <strong>Object</strong><br />
set<strong>Object</strong>(object : <strong>Object</strong>) : void<br />
getElementBelow() : Element<br />
setElementBelow(element : Element) : void<br />
<strong>Object</strong><br />
public void pop() {<br />
topElement = topElement.getElementBelow(); // huidige top overslaan<br />
// de garbagecollector doet de rest<br />
}<br />
Voor het inzichtelijk maken van deze acties, is het altijd handig om voor jezelf object plaatjes te<br />
maken, welke je dat stap voor stap opbouwd. Dezelfde strategie van toevoegen en verwijderen kun<br />
je ook gebruiken bij het implementeren van LinkedList versies van de Queue en de Sequence (en<br />
andere List-vormen).<br />
object<br />
elementBelow<br />
111
L6.3 Analyse van een lijst<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Een lijst is een reeks objecten. Deze reeks objecten heeft een bepaalde volgorde. Deze volgorde is<br />
bepaald door de plaats waar en tijdvolgorde waarin we in de verschillende objecten toevoegen en<br />
verwijderen. Voor de implementatie wordt gebruik gemaakt van elementen die de te plaatsen<br />
elementen beheren, teneinde te voorkomen dat objecten die we ooit in een lijst kwijt willen zelf<br />
deze functionaliteit moeten herbergen. We hebben nu nog de keuze om een dubbel of enkel<br />
gelinkte lijst uitwerken. Een enkele biedt alleen de mogelijkheid om van voor naar achter door de<br />
lijst te werken terwijl de dubbel gelinkte lijst in beide richtingen kan werken. Dit laatste kost echter<br />
meer overhead.<br />
first<br />
Analyse met NIAM van een dubbel gelinkte lijst levert het volgende IGD:<br />
heeft volgende *<br />
heeft vorige *<br />
Element<br />
is sentinel *<br />
Lijst Nummer<br />
is leeg *<br />
wijzer van staat achter de lijst *<br />
Element Element Element<br />
next next next<br />
object<br />
<strong>Object</strong><br />
object<br />
<strong>Object</strong><br />
heeft element met <br />
heeft vorig <br />
heeft volgend <br />
wijzer van staat op <br />
object<br />
<strong>Object</strong><br />
bevat <br />
<strong>Object</strong><br />
112
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Dit resulteert in de volgende classes en attributen<br />
• Class LinkedList<br />
• Element huidige<br />
• boolean leeg //afleidbaar<br />
• boolean heeftVolgende //afleidbaar<br />
• boolean heeft<strong>Object</strong> //afleidbaar<br />
• boolean isAchterLijst //afleidbaar<br />
• Class Element<br />
• Lijst lijst // vervalt<br />
• Nummer nummer // vervalt<br />
• Lijst aangewezenDoor // vervalt<br />
• Element volgende<br />
• <strong>Object</strong> object<br />
• boolean isSentinel // afleidbaar<br />
• Class <strong>Object</strong> // standaard java root class<br />
• Class Nummer // elementnummer (vervalt door referentieadres)<br />
Dit levert het volgende class Diagram op, uitgebreid met de methoden insert, set, get en remove<br />
LinkedList<br />
isEmpty() : boolean<br />
hasNext() : boolean<br />
next() : void<br />
-current<br />
reset : void<br />
clear() : void<br />
insert(object : <strong>Object</strong>) : void<br />
get() : <strong>Object</strong><br />
set(object : <strong>Object</strong>) : void<br />
remove() : void<br />
Element<br />
get<strong>Object</strong>() : <strong>Object</strong><br />
set<strong>Object</strong>(object : <strong>Object</strong>) : void<br />
getNext() : Element<br />
-next<br />
setNext(next : Element) : void<br />
getPrevious() : Element<br />
setPrevious(previous : Element) : void<br />
-object<br />
<strong>Object</strong><br />
Met next kunnen we deze wijzer naar het volgende element verplaatsen, mits deze niet al achter<br />
de lijst staat (hasNext()).<br />
De methode insert voegt voor het huidige element een nieuw element/object tussen. Terwijl de set<br />
het nieuwe object onder de wijzer plaatst, hij vervangt het oude object.<br />
Remove haalt het object onder de wijzer weg en wijst vervolgend naar het (oude) volgende<br />
element.<br />
De add en de remove zijn enigszins lastig vanwege het manipuleren van de referenties. Men raakt<br />
hier licht de draad (lees referentie) kwijt.<br />
Onderstaande object diagram laat de insert zien. De insert plaatst een nieuw element met object<br />
voor de wijzer.<br />
113
L6.3.1 Implementatie van een Lijst<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
De List (of lijst) zoals we hem hier bekijken wijkt enigszins af af van de List zoals deze wordt<br />
gebruikt in de JCF. Wil je er meer over lezen dan kun je bijvoorbeeld het boek Data Structures &<br />
Problem Solving Using Java door Mark Allen Weiss er op naslaan.<br />
Terwijl de List in de JCF met een index werkt, werken we hier met een reeks geschakelde<br />
(gelinkte) dynamische gegenereerde elementen. In een enkel gelinkte lijst bestaat elk element uit<br />
een <strong>Object</strong> referentie en één naar het volgende element.<br />
Om een element in te voegen (insert), moeten we eerst bepalen waar we dit doen. In de gegeven<br />
implementatie is gekozen om het object voor de wijzer in te voegen.<br />
We hebben nu het probleem dat we niet terug in de lijst kunnen (enkele link). Dus niet een nieuw<br />
vorig element kunnen maken omdat we dan de lijst structuur niet kunnen onderhouden, door een<br />
vorig element een nieuwe volgend te geven. We kunnen dit echter eenvoudig oplossen door het<br />
nieuwe element niet voor maar achter de wijzer toe te voegen en vervolgens door de objecten te<br />
verwisselen de juiste volgorde van de objecten, waar het uiteindelijk om gaat, te herstellen.<br />
‘nieuwe’object<br />
<strong>Object</strong><br />
Element<br />
current<br />
<strong>Object</strong><br />
‘nieuwe’element<br />
Element<br />
Element<br />
<strong>Object</strong><br />
Element insert = new Element(); // creëer nieuw element<br />
insert.setNext(current.getNext()); // link deze naar zijn volgende<br />
current.setNext(insert); // link de huidige naar de nieuwe<br />
insert.set<strong>Object</strong>(current.get<strong>Object</strong>); // plaats huidige object in het Element<br />
current.set<strong>Object</strong>(object); // plaats nieuwe object in huidige<br />
current = insert; // verplaats huidige<br />
114
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Bij het verwijderen van een Element uit de lijst kan men niet volstaan met het overslaag van het<br />
huidige element, omdat dit slechts gerealiseerd kan worden vanuit het vorige element die we dus<br />
niet kennen. We passend een soortgelijke handelswijze als bij de insert toe. We verwijderen niet<br />
het wijzer element, maar het volgende, waarbij we onder de wijzer het object van de volgende<br />
gaan bewaren. Uiteindelijk het ik nu het gewenste object verwijderd en mijn structuur in tact<br />
gehouden. Teven staat mijn nieuwe wijzer op de juiste plaats. De garbage collector ruimt<br />
vervolgens het overbodige element en verwijderde object op omdat er niet meer aan wordt<br />
gerefereerd.<br />
Element<br />
current<br />
object<br />
<strong>Object</strong><br />
Element Element<br />
next next next<br />
<strong>Object</strong><br />
object<br />
object<br />
<strong>Object</strong><br />
Een implementatie van de remove vind je in het navolgende uitwerking.<br />
Het verhaal is nog niet compleet. wat gebeurt er als ik niet midden in een langere lijst toevoeg of<br />
verwijder, maar aan de uiteinden. Of wat gaat er mis als de lijst leeg is ?<br />
Sentinel elementen<br />
Als er dus niet een huidig element is om achter toe te voegen of een volgende element is om te<br />
verwijderen hebben we een probleem. We kunnen alle uitzonderingssituaties achterhalen en<br />
hierop in onze code gaan controleren. Dit is een minder gelukkige keuze omdat<br />
uitzonderingssituaties vaak tot bugs leiden. Een mogelijke oplossing is het gebruik van<br />
zogenaamde sentinels. Dit wil zeggen dat we aan het begin van een lijst en/of aan het eind een<br />
extra element toevoegen wat geen object bevat, maar puur bedoeld is om de implementatie te<br />
vereenvoudigen. In de lijst is dan altijd een start en/of een eind element aanwezig. Voor het<br />
voordeel van het voorkomen van uitzonderingssituatie op deze wijze betalen we de prijs van een<br />
enkel (of twee) kleine extra objecten (ruimte).<br />
In de navolgende implementatie wordt gebruik gemaakt van een sentinel aan het einde van de lijst.<br />
Het gebruik van de sentinel blijft voor de ‘gebruiker’ verborgen.<br />
Iterator<br />
In de navolgende implementatie van een Enkel gelinkte lijst is gekozen voor een wijzer in de lijst<br />
zelf. Dit levert problemen op zodra we meerdere wijzers willen gebruiken. Dit probleem kunnen we<br />
oplossen door een extra Iterator-class te maken die een wijzer voor ons beheert en manipuleert.<br />
Deze iterator is, anders dan de ‘gebruiker’ op de hoogte van de interne structuur van de lijst. Deze<br />
uitbreiding is in de implementatie nog niet toegepast.<br />
115
IG9OGO<br />
Sources van een enkel gelinkte lijst.<br />
import nl.hen.ict.assertion.*;<br />
public class SingleLinkedList {<br />
private Element current;<br />
private Element first;<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
public SingleLinkedList() {<br />
first = new Element(); //sentinel;<br />
reset();<br />
}<br />
public void insert(<strong>Object</strong> object) {<br />
Element insert = new Element();<br />
insert.setNext(current.getNext()); //element invoegen<br />
current.setNext(insert);<br />
insert.set<strong>Object</strong>(current.get<strong>Object</strong>()); //objecten plaatsen<br />
current.set<strong>Object</strong>(object);<br />
current = insert; //current opschuiven<br />
}<br />
public void set(<strong>Object</strong> object) {<br />
Assertion.require(hasNext(),<br />
"Kan object niet plaatsen want de wijzer staat op de sentinel");<br />
current.set<strong>Object</strong>(object);<br />
}<br />
public <strong>Object</strong> get() {<br />
Assertion.require(hasNext(),<br />
"Kan object niet opvragen want de wijzer staat op de sentinel");<br />
return current.get<strong>Object</strong>();<br />
}<br />
public void remove() {<br />
Assertion.require(hasNext(),<br />
"Kan niet verwijderen want de wijzer staat op de sentinel");<br />
current.set<strong>Object</strong>(current.getNext().get<strong>Object</strong>());<br />
current.setNext(current.getNext().getNext());<br />
}<br />
public void next() {<br />
Assertion.require(hasNext(),<br />
"Kan de wijzer niet opschuiven want deze staat op de sentinel");<br />
current = current.getNext();<br />
}<br />
public boolean hasNext() {<br />
return !current.isSentinel();<br />
}<br />
public void reset() {<br />
current = first;<br />
}<br />
public void clear() {<br />
first = new Element();<br />
reset();<br />
}<br />
public String toString() {<br />
String result = "";<br />
Element iterator = first;<br />
while (!iterator.isSentinel()) {<br />
result += iterator.get<strong>Object</strong>().toString(); //object afbeelden<br />
iterator = iterator.getNext(); //opschuiven<br />
}<br />
return result;<br />
}<br />
public boolean isEmpty(){<br />
return first.isSentinel();<br />
}<br />
116
}<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
public class Element { // Inner class<br />
private Element next;<br />
private <strong>Object</strong> object;<br />
}<br />
public Element getNext() {<br />
return next;<br />
}<br />
public void setNext(Element newNext) {<br />
next = newNext;<br />
}<br />
public <strong>Object</strong> get<strong>Object</strong>() {<br />
return object;<br />
}<br />
public void set<strong>Object</strong>(<strong>Object</strong> new<strong>Object</strong>) {<br />
object = new<strong>Object</strong>;<br />
}<br />
public boolean isSentinel() {<br />
return object == null;<br />
}<br />
117
OEFENINGEN moduletaak 6<br />
OEFENING 6.1<br />
OEFENING 6.2<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
De bedoeling van deze opgave is om een wachtrij (queue) te maken.<br />
Bij een wachtrij worden nieuwe objecten achteraan toegevoegd en objecten worden aan de<br />
voorkant weggehaald. Het enige object dat toegankelijk is is het voorste object.<br />
Twee voorbeelden van een wachtrij:<br />
Een wachtrij heeft de volgende methoden:<br />
• public <strong>Object</strong> first() (geeft het voorste object)<br />
• public boolean isEmpty() (is de wachtrij leeg?)<br />
• public void remove() (verwijdert het voorste object)<br />
• public void put(<strong>Object</strong> nw<strong>Object</strong>) (voegt een nw<strong>Object</strong> achteraan toe)<br />
Geef een analyse van de datastructuur en ontwerp de datastructuur.<br />
Element dient in de implementatie als inner class te worden opgenomen.<br />
Implementeer de wachtrij. Maak daarbij gebruik van een sentinel achteraan de wachtrij en laat de<br />
elementen verwijzen naar het volgende element.<br />
OEFENING 6.3 (Uitwerken op het systeem en inleveren op het werkcollege)<br />
Een wachtrij op basis van een LinkedList, kan op verschillende manieren geïmplementeerd<br />
worden: met of zonder sentinel(s). Daarnaast zijn de volgende verwijzingen tussen elementen<br />
mogelijk:<br />
• de verwijzingen gaan alleen naar achteren;<br />
• de verwijzingen gaan zowel van voor naar achter als van achter naar voor;<br />
• de verwijzingen gaan alleen naar voren.<br />
Implementeer de wachtrij (en de elementen) op de volgende manieren:<br />
a) zonder sentinels, met verwijzingen alleen naar achteren;<br />
b) met een sentinel vooraan en een sentinel achteraan en verwijzingen naar voren en naar<br />
achteren.<br />
OEFENING 6.4 (Verdieping)<br />
Veel spellen maken gebruik van een rechthoekig speelbord. In deze opgave is het de bedoeling<br />
een speelbord te maken dat bruikbaar is voor diverse spellen.<br />
Enkele eisen voor het speelbord: het speelbord is rechthoekig, de velden worden zowel horizontaal<br />
als vertikaal genummerd van 1 tot en met een maximum in de betreffende richting, een veld kan<br />
leeg zijn, maar het kan ook een speelstuk (dat afhangt van het soort spel) bevatten.<br />
De volgende methoden moeten geïmplementeerd worden:<br />
• public Speelbord(int aantalRijen, int aantalKolommen) (creëert een leeg bord);<br />
• public void put(int rij, int kolom, Stuk stuk) (zet stuk op het bord);<br />
• public void remove(int rij, int kolom) (verwijdert stuk van het bord).<br />
Ontwerp, implementeer en test het boven beschreven speelbord.<br />
118
ZELFTOETS bij moduletaak 6<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
1. Bedenk zelf 2 voorbeelden van toepassingen/situaties voor elk van de collecties: Set, Map,<br />
List, Stack, Queue en Sequence.<br />
2. Welke collectie zou je kunnen gebruiken voor een statements in een methode?<br />
3. Welke collectie zou je kiezen voor de diverse methoden in een class?<br />
4. Welke collectie zou je kiezen voor een spaarvarken?<br />
5. Welke collectie zou je kiezen voor de opstelling van een voetbalelftal?<br />
6. Wanneer lijkt een array (toch een juiste keuze?<br />
7. Wat is het verschil tussen een object een een element?<br />
8. Hoe zou je een implementatie van een simpele Set maken op basis van de LinkedList, Teken<br />
een object-diagram.<br />
9. Bedenk welke collectie voor een (passagiers)trein wagon geschikt zou zijn. Hoe ziet dit er dan<br />
uit voor de hele trein(aaneenschakeling van wagons).<br />
119
PRAKTIKUM OPDRACHTEN.<br />
Opdracht 1. Onroerend goed<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Bij deze opdracht gaat het om een gemeente die in verband met allerlei belastingen en heffingen<br />
de waarde van onroerend goed vaststelt. Voor het gemak gaan we ervan uit dat het onroerend<br />
goed alleen woningen betreft.<br />
Van een woning, die geïdentificeerd wordt door een kadastraal nummer wordt de waarde<br />
vastgelegd.<br />
Een woning kan een bewoner hebben. Er kan maar één bewoner per woning zijn en een bewoner<br />
kan maar in één woning tegelijk wonen. Bij een bewoner hoort altijd een woning.<br />
Verder heeft een woning een eigenaar. Een woning heeft maar één eigenaar, maar een eigenaar<br />
kan meer woningen in bezit hebben. Bij een eigenaar hoort altijd een woning (het omgekeerde<br />
eisen we niet). Van de eigenaar wordt verder vastgelegd bij welke hypotheekbank hij/zij is<br />
aangesloten (dat kan er maar één zijn).<br />
Een eigenaar is altijd ook bewoner. Dit kan zowel van zijn/haar eigen woning als van een andere<br />
zijn.<br />
De waarde van een woning moet in Euro’s worden vastgelegd, maar moet ook in guldens kunnen<br />
worden afgedrukt. Een Euro is gelijk aan fl. 2,20371<br />
De gemeentelijke administratie moet de volgende handelingen kunnen uitvoeren:<br />
Een nieuwe woning moet aan het woningenbestand toegevoegd kunnen worden.<br />
Een bewoner moet aan het bewonersbestand kunnen worden toegevoegd.<br />
Een eigenaar moet aan het eigenaarbestand kunnen worden toegevoegd.<br />
Alle bewoners moeten kunnen worden afgedrukt met de gegevens van de woning (nummer en<br />
waarde in guldens en Euro's en eigenaar).<br />
Alle woningen moeten kunnen worden afgedrukt met hun kadastraal nummer, waarde, eventuele<br />
bewoner en eventuele eigenaar.<br />
De totale waarde van alle woningen moet kunnen worden bepaald. Deze totale waarde moet zowel<br />
in guldens als in Euro's worden afgedrukt.<br />
Gevraagd:<br />
1. Maak een NIAM-analyse van het probleem en laat deze controleren, voorafgaand aan stap 2.<br />
2. Maak een ontwerp voor de software: voer een Classdiagram in Rational Rose .<br />
3. Maak op basis van dit ontwerp een implementatie. Uiteraard dient gebruik te worden gemaakt<br />
van asserties.<br />
Bij de implementatie kunnen een aantal uitgewerkte classes worden gebruikt, waarmee een<br />
eenvoudige user interface wordt gegenereerd met behulp waarvan het te bouwen systeem<br />
soepel kan worden getest. Deze zijn te vinden in /hio/praktikum/i1/OGO/onroerendgoed. Zie<br />
ook de hier aanwezige README-file.<br />
Ingeleverd moeten worden een technisch verslag met daarin opgenomen:<br />
- probleemstelling<br />
- analyse<br />
- ontwerp met daarin van alles een verantwoording, class diagram.<br />
- evaluatie<br />
- de relevante classes (als bijlage en niet in het verslag opgenomen)<br />
Inleverdatum: in overleg met de begeleidende docent.<br />
120
Opdracht 2. Paardensport.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Bij deze opdracht wordt de situatie bij dressuur- en springwedstrijden beschreven. Er zijn een<br />
aantal vereenvoudigingen uitgevoerd waardoor de opgave iets beknopter is, maar waarbij de<br />
realiteit geen geweld is aangedaan. Zo zijn er bijvoorbeeld in werkelijkheid 5 in plaats van 3<br />
klassen.<br />
In de ruitersport worden paarden en ruiters ingedeeld in categorieën en klassen. Er zijn twee<br />
categorieën, dressuur en springen, en drie klassen: L (licht), M (midden), en Z (zwaar). (In<br />
werkelijkheid ook nog B, beginners, en ZZ, zeer zwaar, maar die laten we nu buiten beschouwing.)<br />
Een ruiter is voor een bepaalde categorie ingedeeld in een bepaalde klasse. Een ruiter wordt altijd<br />
meteen in beide categorieën ingedeeld, ook al zal hij/zij maar in één categorie wedstrijden rijden.<br />
Voor een paard geldt hetzelfde. Enkele voorbeelden zijn in de volgende tabellen te vinden.<br />
Ruiter Categorie Klasse Paard Categorie Klasse<br />
Dirk dressuur M Branja dressuur L<br />
Dirk springen L Branja springen M<br />
Danny dressuur Z Peck dressuur Z<br />
Danny springen Z Peck springen Z<br />
Conny dressuur M Bobby dressuur L<br />
Conny springen L Bobby springen L<br />
Wendy dressuur L Quincy dressuur M<br />
Wendy springen Z Quincy springen L<br />
Voor wedstrijden in een bepaalde categorie (dus een springwedstrijd of een dressuurwedstrijd)<br />
komen een ruiter en een paard (een combinatie) uit in een bepaalde klasse.<br />
Een ruiter kan met meerdere paarden in één wedstrijd deelnemen. Ook kan een paard met<br />
meerdere ruiters een combinatie vormen in één wedstrijd. Voorbeelden van combinaties die in een<br />
wedstrijd tegelijkertijd kunnen voorkomen zijn dus: Dirk met Branja, Danny met Branja en Danny<br />
met Peck.<br />
De klasse waarin de combinatie uitkomt wordt bepaald aan de hand van de volgende regels:<br />
Een ruiter die nog niet eerder was ingeschreven wordt ingedeeld in L.<br />
Hetzelfde geldt voor een paard.<br />
Een L-ruiter start met elk paard in klasse L.<br />
Een M-ruiter start met een L-paard in klasse L.<br />
Een M-ruiter start met een M- of Z-paard in klasse M.<br />
Een Z-ruiter moet met een L-paard in M starten.<br />
Een Z-ruiter start met een M-paard in M.<br />
Een Z-ruiter start met een Z-paard in Z.<br />
Verder geldt ten aanzien van de puntentelling bij wedstrijden het volgende.<br />
Bij een wedstrijd haalt een combinatie (van ruiter en paard) een aantal punten van 0 tot en met<br />
260. Dit puntenaantal wordt vertaald in winst- of verliespunten: 118 t/m 155 wedstrijdpunten<br />
leveren géén winstpunten op; 156 t/m 168 wedstrijdpunten (60-65% score) leveren 1 winstpunt op;<br />
169 t/m 181 wedstrijdpunten ( 65-70% score) leveren 2 winstpunten, 182 of meer wedstrijdpunten<br />
(>=70 % score) leveren 3 winstpunten; 104 t/m 117 wedstrijdpunten( 40 <strong>–</strong> 45 % score) leveren 1<br />
verliespunt op, 91 t/m 103 wedstrijdpunten ( 35-40 % score) leveren 2 verliespunten en 90 of<br />
minder wedstrijdpunten ( score < 35 %) leveren 3 verliespunten.<br />
De winstpunten gelden niet individueel, maar voor een combinatie. Bij 10 of meer winstpunten gaat<br />
de combinatie over naar de volgende klasse. Dit kan dus nooit gebeuren met één wedstrijd. Na<br />
promotie begint de combinatie weer met 0 winstpunten.<br />
Voorbeeld:<br />
Een combinatie van een L-ruiter met een Z-paard start in L. Bij 11 winstpunten gaat de combinatie<br />
over naar klasse M. Dat betekent dat alleen de ruiter een klasse hoger (M) komt; het paard blijft Z.<br />
Wanneer beiden (in een bepaalde categorie) in dezelfde klasse zouden zitten, promoveren ze ook<br />
beide.<br />
De wedstrijdadministratie vindt plaats bij de ruitersportfederatie. Hier wordt ook de indeling<br />
121
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
in klassen geadministreerd.<br />
Bij de federatie moeten een aantal zaken worden uitgevoerd:<br />
• Een ruiter moet kunnen worden ingeschreven. Dit gebeurt tegelijk voor beide categorieën.<br />
(Naam en adres opgeven; indeling automatisch in klasse L voor beide categorieën.)<br />
• Een paard moet kunnen worden ingeschreven. (Naam van het paard en die van de eigenaar<br />
opgeven. Indeling in klasse L voor beide categorieën.)<br />
• Vóór een wedstrijd moeten combinaties kunnen worden gevormd. Dat wil zeggen dat een ruiter<br />
en een paard gekoppeld moeten kunnen worden. Een paard kan tegelijk met meer ruiters en<br />
elke ruiter met meer paarden ingeschreven staan; elke combinatie heeft zijn eigen<br />
puntenaantal en klasse.<br />
• Vóór een wedstrijd moet voor een combinatie van ruiter en paard een startbewijs afgedrukt<br />
kunnen worden. Dit is een bewijs waarop staat in welke klasse de combinatie mag uitkomen.<br />
Er staan dus vier dingen op: naam ruiter, naam paard, categorie en klasse.<br />
• Ná een wedstrijd moet het aantal wedstrijdpunten van een combinatie van ruiter en paard in<br />
een bepaalde categorie in een bepaalde klasse kunnen worden ingevoerd. Aan de hand van<br />
deze wedstrijdpunten worden winstpunten bepaald en geadministreerd.<br />
• Na invoering van de wedstrijdresultaten moeten promoties kunnen worden uitgevoerd.<br />
Verder moeten<br />
• een overzicht van alle paarden (met al hun gegevens) gemaakt kunnen worden;<br />
• een overzicht van alle ruiters (met al hun gegevens) gemaakt kunnen worden.<br />
Gevraagd:<br />
Maak eerst een NIAM-analyse en ontwerp op basis daarvan de software voor de administratie van<br />
de ruitersportfederatie. Uit bovenstaande lijst met punten kunnen daarna vrij eenvoudig de nodige<br />
use cases afgeleid worden. Maak een plan van aanpak met betrekking tot de volgorde waarin je de<br />
use cases implementeert. Je mag maar met één use case tegelijk bezig zijn, de eerder<br />
geïmplementeerde moeten werken en blijven werken.<br />
Bij de implementatie kunnen een aantal uitgewerkte classes worden gebruikt, waarmee weer een<br />
eenvoudige user interface wordt gegenereerd met behulp waarvan het te bouwen systeem soepel<br />
kan worden getest. Deze zijn te vinden in /hio/praktikum/i1/OGO/paardensport. Zie ook de hier<br />
aanwezige README-file.<br />
Ingeleverd moeten worden een technisch verslag met daarin opgenomen:<br />
- probleemstelling<br />
- analyse<br />
- ontwerp met daarin van alles een verantwoording. Class, Use case , Use case Realizations met<br />
Sequence diagrams, voor elke flow of events één.<br />
- evaluatie<br />
- de relevante classes (op regeldrukkerpapier als bijlage en niet in het verslag opgenomen)<br />
Inleverdatum: in overleg met de begeleidende docent.<br />
122
BIJLAGEN<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
BIJLAGE A. UML Quick Reference for Rational Rose 2000<br />
To make modeling with the UML in Rational Rose easier, we’ve provided you with this quick<br />
reference guide.<br />
• General purpose concepts/use-case diagram<br />
• Class diagram- types of classes<br />
• Class diagram- relationships<br />
• Class diagram- more relationships<br />
• Class diagram- visibility & properties<br />
• State-transition diagram- states & transitions<br />
• State-transition diagram- nested states<br />
• Sequence diagram<br />
• Collaboration diagram<br />
• Component/deployment diagrams<br />
123
1.<br />
2.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
124
3.<br />
4.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
125
5.<br />
6.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
.<br />
126
7.<br />
8.<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
127
9<br />
IG9OGO<br />
.<br />
10.<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
128
UITWERKING Zelftoets bij moduletaak 1<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
BIJLAGE B. Uitwerkingen van de zelftoetsen<br />
1. Wat is het doel van het gebruik van asserties?<br />
ANTWOORD:<br />
asserties zijn een hulpmiddel om software van hoge kwaliteit te realiseren: correct en robuust<br />
Tijdens de ontwikkelingsfase werken ze als controle op de precondities, na afronding van de<br />
ontwikkeling dienen ze als documentatie : van welke precondities wordt uitgegaan en welke<br />
postcondities worden gerealiseerd.<br />
2. Wat verstaat men onder Design by Contract?<br />
ANTWOORD:<br />
Design by contract geeft aan dat er software ontwikkeld wordt volgens een contract tussen<br />
leverancier en gebruiker van bestaande software.<br />
De voorwaarden waaronder de te gebruiken bestaande software goed functioneert liggen vast<br />
en de resultaten, bij gebruik overeenkomstig de voorwaarden.<br />
3. Leg het verschil uit tussen pre- en postcondities.<br />
ANTWOORD:<br />
Preconditie: formulering van de voorwaarden waaronder een methode (procedure/functie)<br />
gebruikt mag worden, met een gegarandeerd eindresultaat<br />
Postconditie: formulering van gegarandeerd eindresultaat bij gebruik van de bestaande<br />
software volgens de precondities<br />
4. Welke rol vervullen asserties in de testfase en in de opleveringsfase?<br />
ANTWOORD:<br />
Zie antwoord op vraag 1.<br />
5. Welke verantwoordelijkheid heeft de “client” ten aanzien van het gebruik van precondities?<br />
ANTWOORD:<br />
De gebruiker TEST ! Met andere woorden: De client moet voorafgaand aan het gebruik van<br />
bestaande software controleren of aan de precondities (voorwaarden) ervan is voldaan.<br />
6. Ligt de volgende uitspraak toe:<br />
“Asserties zijn niet bedoeld ter vervanging van input controle”<br />
ANTWOORD:<br />
Omdat asserties in de test of ontwikkelingsfase als controle op precondities van bestaande<br />
software werken, wordt gemakkelijk de vergissing gemaakt dat gegevens die door een<br />
systeemgebruiker worden ingevoerd dan niet meer gecontroleerd hoeven te worden. Dit moet<br />
wel degelijk apart gebeuren: immers de “client” moet zorgen dat aan de precondities is voldaan<br />
en dit kan input controle vereisen<br />
7. Voeg in onderstaande constructor van Persoon een correct gebruik van asserties toe.<br />
/* persoon registreert gegevens van een patient geidentificeerd door een naam<br />
tevens wordt de geboortedatum bijgehouden en de huisarts van deze patient<br />
*/<br />
import nl.hen.ict.assertion.Assertion;<br />
class Persoon{<br />
private String naam; //identificatie<br />
private Arts huisArts;<br />
private String gebDatum;<br />
}<br />
public Persoon(String nwNaam, String nwGebDatum){<br />
Assertion.require((nwNaam != null) AND (nwGebDatum!=<br />
null),”nwNaam mag niet null zijn en nwGebDatum mag niet null<br />
zijn”);<br />
naam= nwNaam;<br />
gebDatum= nwGebDatum;<br />
}<br />
129
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
8. Geef aan hoe op een correcte manier in een hoofdprogramma een Persoon object wordt<br />
aangemaakt volgens het “contract” van vraag 7.<br />
IG9OGO<br />
ANTWOORD 8<br />
String nwNaam ;<br />
String nwGebDatum ;<br />
……..<br />
………<br />
……<br />
// nu is niet zeker of nwNaam en nwGebDatum naar een string verwijzen!!<br />
if ( nwNaam!= null AND nwGebDatum!=null ){<br />
Persoon eenPersoon= new Persoon(nwNaam,nwGebDatum<br />
}<br />
9. Onderstaande codefragment uit het uitgewerkte voorbeeld van deze moduletaak wordt op een<br />
juiste manier “Design by Contract “ toegepast. Licht toe in welke coderegels hiervan sprake is<br />
en leg uit waarom dit een correct gebruik ervan is.<br />
10. public void koppel(String naam, int nummer) {<br />
11. if (rekeninghouderBestaat(naam) && rekeningBestaat(nummer)) {<br />
12. Rekeninghouder rekh = geefRekeninghouder(naam);<br />
13. Rekening rek = geefRekening(nummer);<br />
14. if (!rekh.heeftRekening()){<br />
15. rekh.open(rek);<br />
}<br />
16. else {<br />
17. System.out.println(“Rekeninghouder heeft al<br />
rekening”);<br />
18. }<br />
}<br />
19. else {<br />
20. System.out.println(“Rekeninghouder en/of rekening<br />
onbekend”);<br />
21. }<br />
22. }<br />
ANTWOORD:<br />
r 11 en r14 testen door de gebruiker ingevoerd om aan de precondities te voldoen van de<br />
gebruikte methoden:<br />
voor geefReninghouder: rekeninghouder moet bestaan<br />
voor geefRekening: rekening moet bestaan<br />
voor open ( ) : rekeninghouder mag nog geen rekening hebben.<br />
Als niet aan deze voorwaarden is voldaan worden de methoden niet aangeroepen en wordt<br />
dit op het scherm aan de gebruiker gemeld.<br />
130
UITWERKING Zelftoets bij moduletaak 2<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
1. Welke elementen uit een NIAM IGD worden standaard omgezet naar een class bij afbeelding<br />
naar een ontwerp van classes?<br />
ANTWOORD:<br />
Elk objecttype wordt in principe een class, elke nominalisatie wordt een class ,elk n-air feittype<br />
met n>=3 , wordt ook een class<br />
2. Welke constructoreisen volgen uit een NIAM IGD bij het <strong>ontwerpen</strong> van een class?<br />
ANTWOORD:<br />
Identificatie attributen moeten als parameter meegegeven worden in de constructor, evenzo<br />
de attributen die afgeleid zijn uit een feittype waar een veplichtingsregel voor geldt.<br />
3. Wanneer kunnen er in afwijking van de formele afbeelding naar het ontwerp van classes<br />
vereenvoudigingen worden toegepast? Geef een toelichting.<br />
ANTWOORD:<br />
O.a. Als een objecttype maar in één feittype voorkomt hoeft doorgaans geen aparte class te<br />
worden gedefinieerd maar kan volstaan worden met een attribuut in de corresponderende<br />
class<br />
4. Zet het volgende NIAM IGD om naar een ontwerp van classes:<br />
Land<br />
Sitenaam<br />
[NL, DE, CH]<br />
Site<br />
N L<br />
In is een site met<br />
<br />
hen NL<br />
Knoop<br />
Subnet<br />
S SN M<br />
in op is een<br />
netwerkknoop<br />
hen.NL hio bach<br />
Message<br />
K1 K2 T<br />
Machine<br />
M U<br />
Tijdstip<br />
K S<br />
heeft het beheer over in<br />
subnet “hio”<br />
K S<br />
heeft het beheer<br />
over <br />
is bestemd voor <br />
bach@hio.hen.nl \ 12 karel<br />
op is van naar een<br />
bericht verzonden<br />
bach@hio.hen.nl<br />
rome@cs.ibm.de<br />
12<br />
M T<br />
bevat <br />
bach@hio.hen.nl \ 12 hallo<br />
is systeembeheerder<br />
Voor de eenvoud reduceren we meteen maar:<br />
Sitenaam -> String<br />
Land -> String // denk wel om class-invariant wanneer het land gebruikt wordt!<br />
Subnet -> String<br />
Machine -> String<br />
Tijdstip -> String<br />
Tekst -> String<br />
Waarschijnlijk zullen in de praktijk Subnet, Machine en mogelijk Tijdstip classes blijven.<br />
User<br />
*<br />
Systeembeheerder<br />
Afgeleid feittype bevat feiten over alle knopen in het subnet “hio”<br />
U<br />
Tekst<br />
131
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Essentie die overblijft:<br />
class Site<br />
String naam // identificatie<br />
String land // identificatie<br />
Set behoortTot // Knoop<br />
Invariant:<br />
naam != null<br />
land.equals("NL") or land.equals("DE") or land.equals("CH")<br />
behoortTot != null<br />
class Knoop<br />
String machine // identificatie<br />
String subnet // identificatie<br />
Site site // identificatie<br />
Systeembeheerder beheerder<br />
Systeembeheerder hioBeheerder // functie<br />
Set verzondenMessages // Message<br />
Set ontvangenMessages // Message<br />
Invariant:<br />
machine != null<br />
subnet != null<br />
site != null<br />
verzondenMessages != null<br />
ontvangenMessages != null<br />
hio_beheerder == beheerder, als subnet.equals(“hio”)<br />
class Message<br />
Knoop verstuurdVan // identificatie<br />
String tijdstipVerzending // identificatie<br />
Knoop verstuurdNaar<br />
User geadresseerde<br />
String inhoud<br />
Invariant:<br />
verstuurdVan != null<br />
tijdstipVerzending != null<br />
verstuurdNaar != null<br />
geadresseerde != null<br />
inhoud != null<br />
class User<br />
String naam // identificatie<br />
Message ontvangenMessage<br />
Invariant:<br />
naam != null<br />
class Systeembeheerder extends User<br />
Set beheerderVan // Knoop<br />
Set beheerderIndienHioKnoop // Knoop<br />
// alleen relevant bij beheerder van hio-knoop, dus weg<br />
// (zie ook functie in class knoop)<br />
Invariant:<br />
beheerderVan != null<br />
Je zou bovendien verwachten dat een systeembeheerder minstens één systeem<br />
beheert, maar dat is hier niet zo (vergeten?)<br />
132
UITWERKING Zelftoets bij moduletaak 3<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
1. Waarom <strong>ontwerpen</strong> we aan de hand van modellen?<br />
ANTWOORD:<br />
Visuele modellen helpen omgrotere systemen eenvoudiger te begrijpen en vergemakkelijken<br />
de communicatie over de structuur van systemen. Bovendien kan het documenteren van een<br />
systeem op een meer uniforme en volledige wijze plaatsvinden<br />
Resultaat: kwalitatief betere software.<br />
2. Welke views vormen de basis van UML modellering in RationalRose? Wat is de betekenis<br />
ervan?<br />
ANTWOORD:<br />
Use Case View de functionaliteit van het systeem wordt weergegeven zoals deze door de<br />
externe gebruikers (actors) wordt waargenomen.<br />
Logical View statische structuur van classes geeft de functionaliteit binnen het systeem<br />
Component View weergave groepering van code componenten<br />
Deployment View model voor afbeelding softwareonderdelen op hardware , gedistribueerd en<br />
niet gedistribueerd<br />
3. Wat zijn associaties en aggregaties? Met welke symbolen zijn deze in UML aan te geven?<br />
ANTWOORD:<br />
Een associatie is een relatie tussen classes waarbij een object van een bepaalde class A een<br />
object van een andere class B kent. Bij een aggregatie is de relatie sterker: een object van<br />
class A beheert dan een object van class B, dat wil zeggen: de levensduur van object van<br />
class B is gekoppeld aan de levensduur van object van class A.<br />
4. Wat is het doel van een use case diagram?<br />
ANTWOORD:<br />
Weergeven welke gebruiken het systeem benutten: systemen en personen<br />
Weergeven bij welke onderdeel (use case) elke gebruiker (actor ) betrokken is<br />
Ook is het mogelijk de onderliggende opbouw van use cases te tonen o.a. met extends relatie<br />
5. Wat is het verschil tussen een sequence en een collaboration diagram?<br />
ANTWOORD:<br />
Sequence diagram geeft de samenwerking tussen objecten in het systeem weer met de<br />
nadruk op de tijdvolgorde. Collaboration diagram doet hetzelfde maar dan met nadruk op<br />
welke objecten met elkaar communiceren<br />
6. Maak een class diagram bij de uitwerking van Zelftoets moduletaak 2 vraag 4<br />
ANTWOORD:<br />
-verstuurdVan verstuurdNaar<br />
Site<br />
naam : String -site -behoortTot<br />
Knoop<br />
machine : String<br />
2<br />
Message<br />
tijdstipVerzending : String<br />
land : String<br />
*<br />
subnet : String<br />
inhoud : String<br />
-beheerderVan<br />
SysteemBeheerder<br />
-geadresseerde<br />
7. Ontwerp voor de use case “urenInvoeren “ van het Garagevoorbeeld een<br />
User<br />
naam : String<br />
ontvangenMessage<br />
name<br />
133
IG9OGO<br />
Sequencediagram.<br />
: monteur<br />
voerUrenin(String, Datum, String, float)<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
: Admin : Afspraak : WerkOrder<br />
getKlant(String)<br />
getAfspraak(Klant, Datum)<br />
voerUrenin(String, float)<br />
getWerkOrder( )<br />
setBestedeUren( )<br />
134
UITWERKING Zelftoets bij moduletaak 4<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
5. Wat is een interface in JAVA termen? Noem een voorbeeld van een toepassing.<br />
ANTWOORD:<br />
Een interface heeft tot doel om een scheiding aan te brengen tussen interface en<br />
implementatie: het voor de gebruiker relevante en niet-relevante deel van de te gebruiken<br />
software. Een interface is eigenlijk een abstract class zonder attributen, zlleen de signature van<br />
de methoden wordt vastgelegd.<br />
Voorbeeld: Set interface .<br />
6. Wat is een abstract class? Wat is het nut hiervan?<br />
ANTWOORD:<br />
Een abstract class is een class waarvan geen instanties aangemaakt kunnen worden. Meestal<br />
bevat een dergelijke class één of meer abstracte methoden.<br />
Soms is het niet mogelijk in een superclass een bepaalde methode uit te voeren, terwijl we bij<br />
inheritance toch een dergelijke methode verplicht willen stellen. Een abstract class is dan<br />
handig.<br />
7. Zijn een interface en een abstract class uitwisselbaar? Waarom wel/niet?<br />
ANTWOORD:<br />
Nee, een abstract class mag naast de abstracte methoden ook wel geïmplementeerde<br />
methoden bevatten, een interface niet.<br />
8. De volgende figuur toont een deel van de componentenhiërarchie uit de awt. Container en<br />
Component zijn abstract classes<br />
Component<br />
Container TextComponent<br />
Panel Window<br />
Dialog Frame<br />
TextArea TextField<br />
Gegeven is bovendien nog het volgende:<br />
− De klasse Container heeft een methode add met de volgende signatuur:<br />
public void add(Component c)<br />
− De klassen Window en Dialog hebben constructoren als volgt:<br />
public Window(Frame parent)<br />
public Dialog(Frame parent)<br />
− Een applicatieprogrammeur definieert in een eigen klasse een methode met de volgende<br />
signatuur:<br />
public void voegLettersToe(TextField tf, Window w)<br />
Elk van de volgende programmafragmenten bevat een fout. Geef aan wat er fout is en<br />
wanneer deze fout optreedt, bij vertaling of bij verwerking. Als de fout vermeden kan worden<br />
door een cast toe te voegen, toon dan ook de verbeterde code. Licht je antwoorden kort toe.<br />
a Component c1 = new Panel();<br />
Component c2 = new Frame();<br />
c2.add(c1);<br />
135
IG9OGO<br />
b Window w = new Frame();<br />
Dialog d = new Dialog(w);<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
c TextComponent tc = new TextArea();<br />
Frame f = new Frame();<br />
voegLettersToe((Textfield)tc, f);<br />
ANTWOORD a:<br />
De derde regel geeft bij vertaling een foutmelding; het gedeclareerde type van c2 is Component en<br />
die klasse heeft geen methode add. Met behulp van een cast kan de fout verbeterd worden:<br />
((Container)c2).add(c1);<br />
of<br />
((Frame) c2).add(c1);<br />
ANTWOORD b :<br />
De tweede regel geeft bij vertaling een foutmelding. Het gedeclareerde type van w is Window;<br />
omdat Window > Frame wordt dit als parameter niet geaccepteerd. Ook hier kan een cast worden<br />
toegevoegd:<br />
Dialog d = new Dialog((Frame)w);<br />
ANTWOORD c:<br />
In de derde regel treedt bij verwerking een fout op. Er is (door middel van de cast) beloofd dat het<br />
actuele type van tc TextField zal zijn, maar dat blijkt niet waar: tc is van type TextArea. Tussen<br />
TextArea en TextField bestaat geen relatie en dus is de cast niet uitvoerbaar.<br />
6. Gegeven zijn de volgende klassedefinities.<br />
public class A<br />
{<br />
public int tien(int i)<br />
{ return i+10; }<br />
}<br />
public int twintig(int i)<br />
{ return i+20; }<br />
public class B extends A<br />
{<br />
public int tien(int i)<br />
{ return i*10; }<br />
}<br />
public int superTien(int i)<br />
{ return super.tien(i); }<br />
public class C extends B<br />
{<br />
public int twintig(int i)<br />
{ return i*20; }<br />
}<br />
Geef voor elk van de volgende programmafragmenten aan, of het fragment correct is. Zo<br />
niet, wat is er fout? Zo ja, wat is na afloop de waarde van de variabele resultaat? Licht je<br />
antwoorden kort toe.<br />
a B b = new B();<br />
int resultaat = b.twintig(2);<br />
b A a = new C();<br />
int resultaat = a.tien(2);<br />
c A a = new C();<br />
136
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
int resultaat = a.twintig(2);<br />
d A a = new C();<br />
int resultaat = a.superTien(2);<br />
e B b = new B();<br />
int resultaat = b.superTien(2);<br />
ANTWOORDEN:<br />
a. Klasse B heeft geen methode twintig maar erft deze van A; deze methode wordt<br />
uitgevoerd. Het resultaat is 2+20 = 22.<br />
b. Bij verwerking is het actuele type bepalend. Klasse C heeft geen methode tien maar erft<br />
deze van B; deze methode wordt uitgevoerd. Het resultaat is 2*10 = 20.<br />
c. Bij verwerking is het actuele type bepalend en dus wordt de methode twintig van C<br />
gebruikt. Het resultaat is 2*20 = 40.<br />
d. De vertaler accepteert de tweede regel niet omdat de klasse A (het gedeclareerde type)<br />
geen methode superTien heeft.<br />
e. Nu zijn het gedeclareerde en het actuele type beide B, en dat mag wel want b heeft een<br />
methode superTien. De methode tien van de superklasse van B wordt uitgevoerd; het<br />
resultaat is dus 12.<br />
137
UITWERKING Zelftoets bij moduletaak 5<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
1. Wat is het verschil tussen een Set en een Map?<br />
ANTWOORD:<br />
In een Set worden elementen/objecten geplaatst, terwijl in een Map een value/object via een<br />
key wordt geplaatst<br />
2. Waartoe dient een interface in de Java Collections Classes?<br />
ANTWOORD:<br />
Het interface dient om de functionaliteit van een collectie type vast te leggen, opdat er<br />
implementatie keuzes mogelijk blijven.<br />
3. Welke collection interface kies ik als ik studenten met studentnummer wil gaan registreren?<br />
ANTWOORD:<br />
Een Map (implementatie HashMap).<br />
4. Hoe kan ik in een collectie door de elementen zoeken (bijvoorbeeld een Set of een<br />
LinkedList)?<br />
ANTWOORD:<br />
Door een iterator op te vragen en met deze element na element op te vragen en te<br />
onderzoeken<br />
5. Waarom kan ik bij een map niet direct een iterator opvragen ?<br />
ANTWOORD:<br />
Omdat er in een map sprake is van een entry. Je moet kiezen tussen een iterator op de keys of<br />
op de values.<br />
6. Welke collectie interface en/of implementatie schiet je te binnen bij een parkeerplaats met<br />
genummerde plaatsen?<br />
ANTWOORD:<br />
List met ArrayList<br />
7. Hoe verwijder ik een object uit een Set?<br />
ANTWOORD:<br />
Met de referentie naar het object in de hand kan ik middels remove(object) een element<br />
verwijderen. Eventueel moet ik eerst met een iterator het juiste object in de set gaan zoeken.<br />
8. Hoe gaat een en ander in z’n werk als ik een object ‘uit’ een Map haal?<br />
ANTWOORD:<br />
Met behulp van de key wordt in de Map het juiste object gezocht (door de Map). Wat ik krijg is<br />
een referentie-kopie naar het gevonden object. Het object blijft dus in de collectie aanwezig.<br />
9. Waarom zou ik er voor kiezen om een wrapper rond een bestaande implementatie te maken<br />
met een functionele beperktere interface in plaats van de beschikbare interfaces (zoals List)?<br />
ANTWOORD:<br />
Te veel voor de toepassing niet relevante functionaliteit kan leiden tot foutief gebruik. Dit<br />
verslechtert de robuustheid van de toepassing.<br />
138
UITWERKING Zelftoets bij moduletaak 6<br />
IG9OGO<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
1. Bedenk zelf 2 voorbeelden van toepassingen/situaties voor elk van de collecties: Set, Map,<br />
List, Stack, Queue en Sequence.<br />
ANTWOORD:<br />
….<br />
2. Welke collectie zou je kunnen gebruiken voor statements in een methode?<br />
ANTWOORD:<br />
Sequence<br />
3. Welke collectie zou je kiezen voor de diverse methoden in een class?<br />
ANTWOORD:<br />
Set of Map met signature-key<br />
4. Welke collectie zou je kiezen voor een spaarvarken?<br />
ANTWOORD:<br />
Set<br />
5. Welke collectie zou je kiezen voor de opstelling van een voetbalelftal?<br />
ANTWOORD:<br />
Map<br />
6. Wanneer lijkt een array (toch) een juiste keuze?<br />
ANTWOORD:<br />
Genummerde structuur met vaste lengte, zonder tussenvoegingen en verwijderingen.<br />
7. Wat is het verschil tussen een object een een element?<br />
ANTWOORD:<br />
Een element verzorgt de samenhang tussen de objecten in een lijst<br />
8. Hoe zou je een implementatie van een simpele Set maken op basis van de LinkedList, Teken<br />
een object-diagram.<br />
ANTWOORD : pm.<br />
9. Bedenk welke collectie voor een (passagiers)trein wagon geschikt zou zijn. Hoe ziet dit er dan<br />
uit voor de hele trein(aaneenschakeling van wagons).<br />
ANTWOORD:<br />
Wagon met genummerde zitplaatsen: List (ArrayList).<br />
De trein is een list van wagons, dus een lijst met lijsten.<br />
139
Abstract class, 74<br />
Aggregatie, 47<br />
anonymous inner class, 96<br />
Assertie, 10<br />
Associatie, 47<br />
Class Diagram, 43<br />
Class diagrams, 45<br />
relaties, 46<br />
ClassCastException, 99<br />
Cloneable, 72<br />
collectie types, 83<br />
Collection, 95<br />
Collections, 100<br />
Comparable, 71; 96<br />
Comparator, 96<br />
Correctheid, 10<br />
Design-by-contract, 12<br />
Design-by-Contract<br />
pre- en postcondities, 12<br />
entry, 86<br />
equals, 102<br />
feittype, 109; 110<br />
first in, first out, 92<br />
Gelijkheid van objecten, 102<br />
hashCode, 102<br />
HashSet, 83<br />
Hashtable, 100<br />
implementatie, 82<br />
Implementatie van een lijst, 117<br />
implementatie van een stack, 113<br />
inner class, 96<br />
Inner class, 74<br />
interface, 69; 82<br />
Cloneable, 72<br />
Eigenschappen, 70<br />
Interface<br />
IG9OGO<br />
A<br />
C<br />
D<br />
E<br />
F<br />
G<br />
H<br />
I<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Index<br />
Comparable, 71<br />
Interface Collection, 95<br />
Interface Comparator, 96<br />
Interface List, 99<br />
Interface Map, 99<br />
Interface Set, 95<br />
Interface SortedMap, 99<br />
Interface SortedSet, 95<br />
interfaces, 68<br />
Java Collections Framework, 94<br />
key, 86<br />
last in, first out, 90<br />
lijst, 89; 117<br />
LinkedList, 92<br />
LinkedListStack, 116<br />
list, 117<br />
List, 89; 99<br />
Map, 86; 99; 108<br />
natural ordering, 95<br />
NIAM, 23<br />
ontwerp, 23<br />
omzetting van NIAM, 23<br />
basis, 23<br />
constructorvoorschrift, 25<br />
n-aire feittypen, 27<br />
nominalisatie, 27<br />
Verfijning, 25<br />
Optional operations, 103<br />
peek, 90; 113<br />
pop, 90; 113<br />
Postconditie, 11<br />
Preconditie, 10<br />
push, 90; 113<br />
queue, 110<br />
Queue, 92<br />
RPN, 113<br />
R<br />
J<br />
K<br />
L<br />
M<br />
N<br />
O<br />
P<br />
Q<br />
140
Sequence, 92; 111<br />
Sequence diagram, 44<br />
Sequence Diagram, 52<br />
naming convention, 52<br />
Set, 83; 95; 107<br />
SingleLinkedList, 89<br />
SortedMap, 99<br />
SortedSet, 95<br />
Stack, 90; 109; 114<br />
SuperMarkt, 85; 88<br />
ternaire feittypen, 108<br />
TreeSet, 95; 97<br />
UML, 39<br />
IG9OGO<br />
S<br />
T<br />
U<br />
<strong>Modulehandleiding</strong> <strong>Object</strong> <strong>georiënteerd</strong> <strong>ontwerpen</strong><br />
Diagrammen, 41<br />
Geschiedenis, 39<br />
Overzicht, 40<br />
Quick Reference, 129<br />
Views, 40<br />
uniciteiten, 108<br />
Use case diagram, 42<br />
Use Case Diagram, 48<br />
Use case specification, 50<br />
sjabloon, 50<br />
value, 86<br />
Vector, 100<br />
volgorde, 89<br />
wrapper, 90<br />
V<br />
W<br />
141