01.09.2013 Views

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

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!