Object-geörienteerd denken¶
Denk aan een boom. Wat zie je mentaal voor je? Is het één van deze bomen?
Een boom… | …of deze… | …of deze?1 |
Zeer waarschijnlijk was het niet een van deze bomen. Dat kan ook niet. Er zijn miljoenen bomen over de hele wereld en we kunnen niet allemaal aan dezelfde boom denken. Toch denken we allemaal aan hetzelfde concept van een boom. Dat zou dan ongeveer zo er uit kunnen zien;
Het concept van een boom |
Dit is een weergave van het concept boom. Deze specifieke boom staat nergens. Het is een plaatje. Denk eens na over de eigenschappen van de vorm van een boom? Als we vijf eigenschappen moeten benoemen, waar kom je dan op uit? Zeer waarschijnlijk bedenken we wel dezelfde eigenschappen;
- Een boom heeft een stam
- Aan de stam zitten takken
- Takken kunnen zelf weer kleinere takken hebben
- Aan de takken zitten bladeren
- De boom staat in de grond met wortels
Dit geldt voor bijna alle bomen. Je kan vast ook wel wat uitzonderingen bedenken. Maar je hebt nu niet alle bomen van de hele wereld beschreven. Daarvoor moet je een heel lange en dure reis maken. Je hebt van heel veel objecten uit de wereld vastgesteld dat ze op dezelfde manier zijn te beschrijven, dat er overeenkomsten zijn en dat de eerstvolgende boom die uit een zaadje groeit ook die eigenschappen zal hebben. Je hebt daarmee het concept van een boom vastgesteld. Elke boom zal voldoen aan dat concept, anders noemen we het geen boom. Je kan dit concept niet vastpakken. Het is een abstract begrip. Tegenover abstract staat het begrip concreet. Als er een boom in je achtertuin staat, kan je die zien, voelen, ertegenaan leunen, omhakken. Dit kan omdat die boom concreet is.
We hebben nu vastgesteld dat we als mens kunnen redeneren over concepten. Voor elk abstract concept kan je één of meerdere concrete instanties vinden. Voor het concept boom zijn miljoenen instanties; elke concrete boom is er één. Voor het concept land zijn er honderden. Voor het concept werelddeel zijn er maar een paar. Voor het concept ‘premier van Nederland’ is er niet één maar zijn er meer. Dit omdat ze hebben bestaan maar niet nu meer bestaan. Tijd bepaalt niet of iets bestaat of niet. We kunnen nadenken over het concept “De laatste keizer van het Romeinse Rijk”. Daarvan is er precies één. We kunnen die niet ontmoeten, maar hij was er ooit wel. Concepten bestaan dus als we erover na kunnen denken.
Instanties bestaan of hebben bestaan of kunnen ooit nog gaan bestaan. Ze voldoen in ieder geval aan de beschrijving van het concept. Omdat er voor elk concept één of meer instanties bestaan, noemen we de verzameling van alle instanties een klasse.
Met een klasse bedoelen we de naam en de eigenschappen van het concept waar we over praten. Daar komt nog één beschrijving bij; de methodes. Dat is alles wat de klasse kan doen of wat er met de klasse gedaan kan worden. Bedenk eens vijf voorbeelden van methodes van een boom? Je zou op het volgende uit kunnen komen.
- Een boom kan groeien
- Een boom kan omvallen
- Een boom kan doodgaan
- Een boom kan omgehakt worden
- Iemand kan in een boom een hartje graveren
Schematisch geven we dit als volgt weer;
classDiagram
class Boom {
+Stam
+Takken
+Bladeren
+Wortels
+Groeien()
+Vallen()
+Doodgaan()
+OmgehaktWorden()
+GegraveerdWorden()
}
Bovenaan staat de naam van het concept. Je kan iets heel moeilijk beschrijven als je er geen naam voor hebt. Het is ook moeilijk praten over een concept waar je geen naam voor hebt. De eerste oermensen begonnen al met het benoemen van zaken om over te kunnen praten. Zij zijn dus al begonnen met object-georiënteerd denken.
In het tweede blok staan de eigenschappen. Je hebt al leren programmeren dus je kan die eigenschappen al in een programmeertaal vastleggen. Dat noemen we dan variabelen. Hoeveel takken een boom heeft, is bij elke boom verschillend. Datzelfde geldt voor de bladeren en de wortels. Er is doorgaans maar één stam, maar niet altijd. Je zou dus takken vast kunnen leggen als een getal (een integer), en zo ook voor de bladeren. Je kan nog veel meer zaken vastleggen dan in dit voorbeeld. Wat voor eigenschappen kan je bedenken? Probeer er eens vijf. Bedenk ook het datatype dat erbij hoort. Wellicht zitten jouw vijf in de volgende lijst:
- Type
- Datum geplant
- Locatie
- Hoogte
- Gewicht
- Hoek ten opzichte van de grond
- Kleur stam
- Kleur bladeren
- Vorm bladeren
- Aantal rondingen per blad
- Gemiddelde dikte per wortel
- Langste wortel
Hoe leggen we dan methodes vast? Een methode is “dat een wat de klasse kan doen of wat er met de klasse gedaan kan worden.” Hierbij horen altijd werkwoorden. De boom moet dus iets doen of iemand anders doet het wat een effect heeft op de boom. In het Nederlands herken je dat laatste door te zien dat het boom dan niet meer het onderwerp is van de zin maar het meewerkend voorwerp.
Als dit betekent dat er werkwoorden nodig zijn, dan betekent het in een programmeertaal dat er een functie wordt uitgevoerd. Bij voorbeeld ‘omhakken’. De functie omhakken zal er uit bestaan dat er een aantal keer met een bijl tegen de stam wordt geslagen totdat de boom omvalt. Dit kan dus in een loop worden uitgevoerd. In pseudocode “Zolang de boom niet is omgevallen, hak nog een keer.”
Van functies weten we dat ze een naam hebben een argumenten. Ook levert een functie een nieuwe situatie op. De functie “groeien” zal als argument voedingsstoffen en zonlicht hebben. Het resultaat is een nieuwe boom maar net iets groter en dikker. Bedenk zelf wat de functie “omgehakt worden” beschrijft.
Oefening: Concepten Object georiënteerd programmeren
Er is nu een aantal woorden genoemd die je moet kennen om object-geörienteerd te kunnen denken en praten. Bedenk voor elk van deze woorden een beschrijving:
- Concept
- Abstract
- Concreet
- Definitie
- Klasse
- Instantie
- Eigenschap
- Methode
Hoe objecten aan elkaar relateren¶
Nu we het hebben gehad over één concept en hoe daar mee om te gaan, kunnen we gaan kijken hoe we omgaan met meerdere concepten.
We gaan het daarvoor hebben over een ander concept, de “auto”. Bedenk eens welke eigenschappen en methoden een auto heeft. Je zal ongeveer hier op uitkomen:
classDiagram
class Auto {
+Motor
+Deuren
+Stoelen
+Laadruimte
+Rijden()
+GevuldGeleegdWorden()
+GebouwdWorden()
+GeslooptWorden()
+GetanktWorden()
+PechKrijgen()
+GerepareerdWorden()
}
Stel nu dat je een fan bent van straatracen3. Je hebt een leuke auto die je wel wil ombouwen zodat je er races mee kan winnen. Je wil een andere motor erin hebben. Niet alle motoren passen of zijn geschikt. Je moet je afvragen welke auto welke motor kan hebben. Hiervoor kunnen we het hebben over het concept motor. Dat kunnen we dan relateren aan een auto.
classDiagram
class Auto {
+Motor
+Deuren
+Stoelen
+Laadruimte
+rijden()
+gevuldWorden()
+geleegdWorden()
+gebouwdWorden()
+geslooptWorden()
+getanktWorden()
+pechKrijgen()
+gerepareerdWorden()
}
classDiagram
class Motor {
+Cylinders
+Motorinhoud
+Brandstoftype
+Vermogen
+Lengte
+Laadruimte
+Draaien()
+PechKrijgen()
+GerepareerdWorden()
}
Op enig moment kunnen we de ene motor vervangen door een andere. Het is dus niet voor alle motoren mogelijk, maar dat kan je dus bepalen door te kijken naar de eigenschappen. Je kan er zelfs een functie voor bedenken.
Encapsulatie¶
Nu kunnen we dus de motor van een auto vervangen. We moeten ons dan afvragen? Is het nog steeds dezelfde auto? Is het wel goed als we dit doen of kunnen we problemen tegenkomen? Stel dat je je stadsauto ombouwt en er een racemotor inzet. Nu vraagt je oma of ze de auto mag lenen om boodschappen te doen. Ze stapt er in en rijdt zo tegen een boom vanwege de kracht in de motor. Dit wil je liever niet.
In de wereld van het programmeren wil je dit ook niet. Als je eenmaal iets hebt gebouwd, wil je dat iedereen die hier gebruik van maakt weet wat het is en wat ze er mee kunnen. Daarom willen we dat de eigenschappen niet zomaar kunnen veranderen. Dit kunnen we doen door dit alleen toe te laten via de methodes. Hoe zou de methode kunnen heten waarmee we een andere motor in de auto zetten?
Als we elke verandering aan het object aan kunnen passen via een functie (b.v. “Verander kleur” of “Voeg stoel toe”), dan kunnen we ook de waarde van de objecten ophalen via functies (b.v. “Bepaal motortype”, “Bepaal huidige snelheid” maar ook “Bepaal maximale snelheid”, een functie die nog uitgerekend moet worden). Dit is een manier om het werken met je objecten te beveiligen. Een functie voor zetten van een nieuwe waarde in een eigenschap noemen we een setter. Een functie voor het ophalen van de huidige waarde van een eigenschap noemen we een getter.
Nu we het werken met de eigenschappen van onze objecten hebben beveiligd, hebben we daarmee encapsulatie toegepast. Over de eigenschappen is een soort ‘beschermlaagje’ gegoten.
Overerving¶
Er is nog een andere soort relatie die belangrijk is om object-georiënteerd te kunnen denken. Dat is een relatie die we voor nu “is een soort van” zullen noemen. Dit is nodig omdat allerlei concepten sterk met elkaar te maken hebben.
Je kan bij voorbeeld het concept “Voertuig” bedenken. Dat kan een auto zijn, maar er zijn ook andere voertuigen. Welke eigenschappen heeft een auto wel die een vliegtuig niet heeft? En andersom?
Als we Deze 3 concepten dan aan elkaar relateren, hoe zit dit er dan uit? We slaan nu even de specifieke eigenschappen en methoden over. We kunnen later definiëren welke er nodig zijn.
classDiagram
class Voertuig{
+Eigenschappen
+Methoden()
}
class Auto{
+Eigenschappen
+Methoden()
}
class Vliegtuig {
+Eigenschappen
+Methoden()
}
Voertuig <|-- Auto : is een soort van
Voertuig <|-- Vliegtuig : is een soort van
Je zal zien dat een voertuig eigenschappen en methoden heeft die een auto en een vliegtuig allebei hebben. Waarom zouden we die dan steeds opnieuw definiëren? Laten we in plaats daarvan alle gedeelde eigenschappen en methoden bewaren bij “Voertuig” en dan alleen de nieuwe eigenschappen en methoden bij het specifieke voertuig. De rest krijgen ze dan van de bovenliggende klasse. Dit noemen we overerving. Dit heet natuurlijk zo omdat het op dezelfde manier gaat als wanneer kinderen eigenschappen van hun ouders overerven. Twee kinderen van dezelfde ouder kunnen bij voorbeeld de haarkleur overerven, maar dat is niet altijd het geval natuurlijk. In klassenmodellen definiëren we die overerving die zeker wel altijd plaatsvindt.
Polymorfisme¶
Soms kan je meerdere uitkomsten verwachten bij het uitvoeren van een functie. Je zou bij voorbeeld de functie “Verplaatsen” bij een auto kunnen definiëren. Je kan dan meegeven wat de nieuwe coördinaten van de auto zijn, bv de x-coördinaat en de z-coördinaat4. Maar als ik de auto oppak met een grijper, dan gaat dit heel anders dan wanneer ik de auto aanzet en vooruit rijdt. In het eerste geval kost het de auto geen brandstof, in het andere geval wel.
Een functie kan dus meerdere varianten of vormen hebben. Dit noemen we polymorfisme. Verschillende vormen kunnen ook verschillende argumenten hebben. Het verplaatsen van de auto met de motor kan worden uitgevoerd door op te geven hoeveel gas je geeft en hoe lang en dan hoe je niet de x- en z-coördinaten zelf te bepalen want dit kan de auto zelf ‘bepalen’.
-
De HvA raadt dit af ↩
-
In de wereld is het de afspraak dat de y-coordinaat de verticale coordinaat is, dus de richting omhoog en naar beneden. Ter versimpeling denken we hier dat iedereen zich over een vlak aardoppervlak verplaatst. We hebben dergelijke functies ook nodig voor vliegtuigen, dus het is belangrijk om alle 3 de coördinaten op elkaar af te stemmen. ↩