Polymorfisme (informatica)
Polymorfisme staat voor veelvormigheid. In de informatica is polymorfisme een eigenschap die een programmeertaal in mindere of meerdere mate kan bezitten. Polymorf programmeren is de mogelijkheid een algoritme uit te drukken zonder dat de programmeur aandacht moet besteden aan alle verschillende gegevenstypes.[1]
In objectgeoriënteerd programmeren wordt hiermee bedoeld: het gelijkvormig zijn van de interface van klassen en objecten, maar met verschillende implementaties. De gelijkvormigheid betreft dan voornamelijk het gebruik en de naamgeving van operaties (of methodes). Polymorfisme is een van de vier kenmerken die de definitie van objectgeoriënteerd programmeren bepalen.
Voorbeelden
Plusoperator
Een zeer bekend voorbeeld van polymorfisme in programmeertalen is het gebruik van de plusoperator om getallen op te tellen. Als in een fictieve programmeertaal de volgende code verschijnt
int a a = 1 + 2
dan wordt de plus door de compiler vertaald naar een ADD-instructie op machinetaalniveau.
Als in dezelfde fictieve taal de volgende code verschijnt
float a a = 1.0 + 2.0
dan wordt het plusteken door de compiler naar heel andere code vertaald, namelijk naar de code voor het optellen van floating point getallen. De plusoperator betekent in deze gevallen technisch dus iets heel anders, maar logisch gezien doen ze hetzelfde, namelijk optellen. Dat soort gelijkvormigheid is de essentie van polymorfisme.
Het gebruik van de plusoperator in Java om strings aan elkaar te plakken is in dit licht niet correct. Ook de unaire plus en min om het teken van een getal aan te geven (bijvoorbeeld -1) is niet polymorf. Beide voorbeelden zijn voor de argeloze lezer echter meteen duidelijk. Dit toont aan dat polymorfisme, alhoewel zeer belangrijk, niet in alle gevallen zaligmakend is.
De techniek van het gebruik van een operatie (in dit geval de plus) met argumenten van verschillende types en aantallen heet overloading. Alle moderne programmeertalen kennen dit.
Grafische interface
Polymorfisme kan in combinatie met overerving ook worden gebruikt voor het omzeilen van de strenge controle in sommige talen op het type van gebruikte variabelen. Zo was het in standaard Pascal onmogelijk een lijst te definiëren waarvan de onderdelen niet allemaal hetzelfde type hebben. Een voorbeeld daarvan is een lijst controls in een dialoogbox. Wanneer een dialoogbox op het scherm wordt gezet moeten alle controls zichzelf afbeelden. Deze opdracht krijgen die controls van het dialoogboxobject dat daarvoor hun draw-methode aanroept. De programmeur van de dialoogboxklasse hoeft geen rekening te houden met welke controls er allemaal zijn en dezelfde code werkt voor dialoogboxen met zeer verschillende controls.
Overerving
Binnen het objectgeoriënteerd programmeren wordt polymorfisme vaak met overerving in verband gebracht. Overerving is, net als overloading, een manier om polymorfisme te bevorderen. Stel u heeft een basisklasse Dier gemaakt met daarin een operatie AantalPoten() om het aantal poten op te vragen. Alle klassen die afgeleid zijn van deze klasse (bijvoorbeeld de klasse Hond) zal automatisch dezelfde naam gebruiken voor het aantal poten.
Naamconventies
Met alleen overerving kom je er niet. Om polymorfisme te bereiken moet de naamgeving consequent zijn, ook op plekken waar geen sprake is van overerving. Als bijvoorbeeld een (basis)klasse Meubelstuk gedefinieerd wordt moet ook hier de naam AantalPoten() gebruikt worden om het aantal poten op te vragen. Hiervoor is het niet nodig een OO-programmeertaal te gebruiken.
Dit kan alleen bereikt worden als de naamgeving van klassen en vooral van operaties vastgelegd wordt. Hierboven is steeds de naam AantalPoten() gebruikt, maar in het afsprakendocument kan het ook anders beschreven staan. Een aantal mogelijkheden zijn bijvoorbeeld: Een operatienaam ...
- ... begint met een kleine letter. aantalPoten()
- ... begint met get als het een leesoperatie is. getAantalPoten()
- ... bestaat uit alleen een zelfstandig naamwoord. Poten()
- ... gebruikt underscore als scheidingsteken tussen woorden. aantal_poten()
Bij programmeertalen waarin de naam slechts een beperkt aantal tekens lang mag zijn is de naam vaak erg cryptisch voor mensen die de naamconventies niet kennen. Hier is het gebruik van naamconventies nog belangrijker.
Goed toepassen
Dit impliceert dat polymorfisme ook verkeerd toegepast kan worden. Het kan op minstens twee manieren misgaan.
- Polymorfisme moet niet alleen op de naam toegepast worden, maar ook op de argumenten (of parameters) en het returntype van de operatie. Stel, we hebben een operatie setAantalPoten() met als argument een integer die het aantal poten bevat. Dit is logisch, en iedereen zal dit intuïtief direct goed gebruiken. Maar in ingewikkeldere gevallen is dit een stuk lastiger. Het is niet zo eenvoudig om hier regels voor te maken zoals in het geval van de naamgeving. Het gebruik van de argumenten dient echter wel consequent te zijn.
- Dezelfde naamgeving kan gebruikt worden terwijl dit niet terecht is. Bijvoorbeeld de operatie AantalPoten() wordt toegepast op een bedrijf om het aantal onderdelen waaruit het bedrijf bestaat aan te geven. Dit is misleidend. In dit geval kan beter de meest correcte naam toegepast worden, AantalOnderdelen().
Doelen van polymorfisme
Polymorfisme zorgt ervoor dat bepaalde onderdelen in een computerprogramma gebruikt kunnen worden alsof ze van een bepaald abstract type zijn. Het is soms niet wenselijk/noodzakelijk om de precieze implementatie te weten van een object maar volstaat de kennis dat het gaat om een bepaald abstract object.
Polymorfisme zorgt voor uitbreidbaarheid. Het is door gebruik van polymorfisme eenvoudig om nieuwe types te definiëren die een implementatie zijn van een bepaalde interface / abstracte klasse zonder dat dit grote consequenties heeft voor de rest van het product.
- ↑ David M. Harland, "Polymorphic Programming Languages - design and implementation," Ellis Horwood, Chichester (UK) 1984.