Objectgeoriënteerd Programmeren: WPO 1 1. Inhoud Klassen, objecten, methoden, properties, private vs. object, this. public, velden, instantie, reference to 2. Inleiding 2.1 Objecten en klassen 2.1.1 Punt (X, Y) In deze reeks demo s zullen we de basis zien van klassen en objecten. Tijdens deze demo s zullen we de klasse Punt definiëren en instantiëren. Een punt wordt in 2D bepaald door een X en een Y waarde. Opdracht: Schrijf een programma dat toelaat om een X en Y waarde bij te houden en deze door te gebruiker in te vullen. Geef deze waarden ook weer in een label. Maak de X- en Y-variabelen globaal aan. 2.1.2 Klasse Punt Punten laten toe voorwerpen op een 2D-map uit te zetten. De aanpak van hiernet laat niet echt toe om de X- en Y-waarden als een effectief punt te beschouwen. Deze zijn als het ware nog niet aan elkaar gelinkt. C# laat toe om deze waarden onder te brengen in 1 overkoepelend geheel; de klasse. Opdracht: Schrijf de klasse Punt waarin de variabelen X en Y in opgenomen zijn. 2.1.3 Methoden Door het onderbrengen van de X en Y variabelen (velden) in de nieuw aangemaakte klasse kan men deze waarde als gelinkt beschouwen. Echter zijn er binnen het objectgeoriënteerd programmeren een aantal spelregels. Eén van deze regels is dat men de variabelen van een klasse zo veel mogelijk private houdt. Hierdoor zijn deze waarden enkel beschikbaar binnen de klasse Punt. Deze afscherming van de variabelen naar buitenaf biedt als voordeel dat men een volledige controle behoudt over de inhoud van deze variabelen. Dit kan bv. nuttig zijn om te verhinderen dat een programmeur negatieve waarden in deze variabelen zou willen schrijven. Deze beperking impliceert echter wel dat er methodes moeten zijn die deze variabelen kunnen aanpassen en kunnen teruggeven. In die methodes kunnen dan de nodige condities geïmplementeerd worden. Opdracht: Zorg ervoor dat de variabelen X en Y private zijn. Schrijf de nodige methodes om de waarden terug te geven en voorzie methodes om ervoor te zorgen dat de X en Y waarden beperkt blijven tussen -1024 en 1024. Hint: Ook hier geldt de regel dat een private methode enkel zichtbaar is binnen de klasse 1
zelf. Door de methoden public te declareren, is het mogelijk om deze ook buiten de klasse te gebruiken. 2.1.4 Properties De hierboven beschreven methoden kunnen ook via een verkorte C# notatie geïmplementeerd worden. Deze notatie is hiervoor specifiek ontwikkeld en wordt in C# omschreven als properties (letterlijk: eigenschappen). Properties kunnen als getter, setter of beide geïmplementeerd worden. Opdracht: Herschrijf bovenstaande methoden tot properties (getter, setter of beide). Hint: Ook hier gelden de zichtbaarheidsregels. 2.1.5 Objecten We hebben hiernet een klasse geschreven dat toelaat om een X en Y waarde bij te houden. Deze klasse kan er ook voor zorgen dat de inhoud van deze variabelen beperkt is tussen -1024 en 1024. Om deze klasse effectief te kunnen gebruiken moeten we nog 1 stap ondernemen: de klasse instantiëren tot een object. Dit kunnen we doen zoals beschreven in onderstaand codefragment. Merk op dat deze code typisch buiten de code van de klasse geschreven wordt. Codefragment 1: Instantiëren van de klasse Punt tot een object 1 Punt p1 = new Punt(); De geschreven methoden en properties die een publieke toegang hebben (public) kunnen nu achter het object gebruikt worden. Opdracht: Zorg ervoor dat je een instantie van de klasse Punt kan maken. Vul deze klasse ook in via geschreven methoden en properties. 2.1.6 Bewerkingen Klassen en objecten laten toe om buiten het groeperen van variabelen (velden) en het aanmaken van getters en setters ook meer ingewikkelde operaties uit te voeren. Zo is het bv. mogelijk een een punt met een ander punt op tellen. Hiervoor zullen we een nieuwe methode invoeren die een punt als argument heeft en de X en Y variabelen met de eigen variabelen sommeert. Deze methode is noch een getter, noch een setter maar beïnvloed wel de inhoud van het object. Opdracht: Schrijf de methode die toelaat om een punt met een ander te sommeren. Hint: Een methode ziet er exact hetzelfde uit als een functie. Het grote verschil met een functie is dat een methode een bewerking uitvoert op de variabelen van het object zelf, terwijl een functie enkel bewerkingen op lokale variabelen uitvoert. 2.1.7 Constructor Methoden kunnen net zoals functies om het even welk aantal argumenten hebben en een returnwaarde hebben. De naam van methode maakt functioneel niet uit. Een constructor is een speciale methode die enkel tijdens het aanmaken van een object aangeroepen wordt (cfr. to contruct van bouwen of aanmaken). Vermits de constructor enkel dient om een object aan te maken, retourneert deze dus niets. Daarom ook dat er geen returnwaarde bestaat bij een 2
constructor. De naam van de constructor ligt vast en is dezelfde als de naam van klasse. Het aantal argumenten daarentegen kan willekeurig zijn. Opdracht: Schrijf een constructor die 2 argumenten opneemt. Deze argumenten zijn de initiële waarden voor X en Y. Zorg ervoor dat je de nodige checks ook kan toepassen. 2.1.8 Reference type Variabelen van het type integer, float, double enz. zijn opgebouwd vanuit een primitief datatype. Primitieve datatypen kunnen een bepaalde waarde vasthouden en zijn onmiddelijk beschikbaar naar de programmeur. Objecten worden aan de programmeur op dezelfde wijze voorgesteld: een variabele die rechtstreeks beschikbaar is. Echter is een object een reference naar een instantie. Je kan dit vergelijken als een variabele dat als argument by reference aan een functie doorgegeven wordt. Je werkt dus niet rechtreeks op het object, maar op de referentie naar dat object. Opdracht: Maak opnieuw een object p1 (klasse Punt ). Maak een nieuw variabele p2 aan van datzelfde type, maar maak geen nieuw object aan. Door p2 aan p1 gelijk te stellen wordt de referentie van p2 gelijkgesteld aan dat van p1. Verander nu een eigenschap van p2 en volg via de debugger het verloop van p1. 2.1.9 Static methoden Een laatste vorm van methoden zijn de static methoden. Dit type van methode verschilt in programmatie en gebruik t.o.v. de gewone methoden. Static methoden behoren wel tot de bovenliggende klasse, maar maken geen deel uit van de objecten die uit deze klasse voortvloeien. Het is dus niet mogelijk om bij een object dergelijke methodes aan te roepen. Juist doordat deze methoden geen deel uitmaken van objecten, kunnen deze methoden ook geen invloed hebben hebben op de toestand van het huidige object. Dit type van methoden wordt voornamelijk gebruikt wanneer men functies schrijft die geen directe link kunnen vertonen met een bepaald object. Denk hierbij aan de klasse Math waarin een aantal methoden geïmplementeerd zijn zoals sinus, cosinus, tangens, enz. 2.2 Samenvatting Een object bestaat hoofdzakelijk uit 2 onderdelen. De velden: deze houden de huidige toestand van het object bij. De methoden: deze laten toe om de huidige toestand van het object aan te passen. Een object is de instantie van een klasse. Een klasse (blauwdruk) is het theoretisch model van hoe een object zich zal gedragen of er zal uitzien. De klasse is dus de geschreven code terwijl het object overeenkomt (in gebruik) als een variabele. Een object heeft minimaal 1 constructor. De constructor heeft dezelfde naam als de klasse zelf, heeft een aantal argumenten maar heeft geen returnwaarde. In de constructor kunnen best de velden van het object geïnitialiseerd worden. Properties zijn methoden die enkel als getters en setters mogen gebruikt worden. Deze zijn een verkorte notatie om sneller aan velden via buitenaf te geraken. 3
Andere (klassieke) methoden dienen om complexere handelingen op het object uit te voeren. Elke methode heeft een aantal argumenten (minstens 0) en maximaal 1 returnwaarde. Velden (interne variabelen) worden zoveel mogelijk private gehouden om zo de controle over deze velden te garanderen (binnen bepaalde grenzen houden). Methoden en hulpfuncties binnen het object die niet noodzakelijk zijn voor de buitenwereld worden best private gehouden (behoud van controle). Een object is een referentie naar een instantie van een klasse. Sommige klassen bieden static methoden aan. Deze methoden zijn niet toegankelijk via het object, maar wel rechtstreeks via de klasse zelf. In een klasse kan het keyword this gebruikt worden. Hiermee bedoelt men uitsluitend de interne velden van het object. Zo kan je binnen een methode argumenten hebben met dezelfde namen als de interne velden. De compiler weet dan welke naam op welke variabele slaat. 3. Oefeningen Demo 1: Biljarttafel Demo 2: Kleurcodes A: Softwarelibrary A: Rekenmachine A: Regendruppels A: Converter E: Sinusoidaal E: Snake X: Gravity 3.1 Demo 1: Biljarttafel Schrijf een programma dat een biljarttafel kan simuleren. Maak een klasse Bal aan waarin de nodige eigenschappen van elke biljartbal opgenomen worden. Voorzie nodige getters en setters om de eigenschappen van de biljartbal op een veilige manier te kunnen aanpassen. Beperkingen en features die hierin opgenomen dienen te worden: een biljartbal kan niet buiten het veld komen. De X en Y waarden hebben een boven- en onderlimiet. elk biljartbal heeft een snelheid in de X en Y richting (snelheidsvector) een biljartbal heeft natuurlijk ook een kleur. 4
Voorzie methoden om de biljartbal te kunnen updaten. Het uitrekenen van de nieuwe positie en snelheidsvector gebeurt binnen de klasse Bal zelf. Een voorbeeld van deze applicatie kan teruggevonden worden in figuur 1. Figuur 1: Voorbeeld biljardtafel 3.2 Demo 2: Kleurcodes Schrijf een programma die het mogelijk maakt om de kleurcodes van weerstanden uit te rekenen. Volgende functies worden voorzien: een functie om een enkele kleur (string) om te zetten in een getal, een functie om een getal van 0 t.e.m. 9 om te zetten in een kleur (string), een functie om 3 opeenvolgende kleuren (array van string) om te zetten in een weerstandswaarde en, een functie om een weerstandswaarde om te zetten in 3 kleuren (array van string) Maak bij de implementatie van dit programma gebruik van een klasse met static methoden. 3.3 A: Softwarelibrary Software wordt typisch bijgehouden in softwarebibliotheken. Hierbij worden per stuk software de volgende eigenschappen bijgehouden. de programmeur (of naam van de groep), de naam van de software, 5
het versienummer van de software (integer). de datum van uitgave (dag, maand en jaar) Schrijf een applicatie die toelaat om de referenties van de stukken software bij te houden. Voorzie hiervoor een lijst die een klasse Software bijhoudt. Deze klasse bevat minimaal bovenvermelde eigenschappen tezamen met de nodige getters en setters. Volgende beperkingen en features worden voorzien in deze applicatie. Elk stuk software komt maximaal 1 keer voor. Hiervoor wordt op de naam van de software vergeleken en wordt enkel de meest recente versie bijgehouden (hoogste versienummer). Bouw deze vergelijking in het object zelf. Indien een stuk software 2 maal zou voorkomen maar geschreven is door verschillende programmeurs, wordt gevraagd welke versie bijgehouden moet worden. Ook deze vergelijking wordt binnen de klasse zelf uitgevoerd. De lijst met stukken software wordt in een listbox weergegeven. Tijdens dit WPO wordt er geïtereerd over de hele lijst om element per element in de listbox toe te voegen. In volgende WPO s zullen we hiervoor een snellere manier zien (via overerving). De gebruiker kan stukken software toevoegen en verwijderen. De checks worden tijdens het invoegen uitgevoerd waarbij de functie zichzelf met een ander object gaat vergelijken. 3.4 A: Rekenmachine Matlab en andere gelijkwaardige wiskundige software laten toe om wiskundige vergelijkingen uit te rekenen. In deze opgave zullen we een gelijkaardig programma schrijven dat de gebruiker toelaat om eenvoudige vergelijkingen bestaande uit 2 getallen en een operator uit te rekenen. Laat de gebruiker toe om achtereenvolgens een getal, een bewerking en een getal in te geven. Houd de 2 getallen (en het resultaat) en de operator in een object bij en reken de uitkomst uit. Matlab houdt een geschiedenis bij van de voorgaande ingevoerde bewerkingen. Houd dus net zoals Matlab de bewerkingen bij in een geschiedenisvenster (zie figuur 2). Figuur 2: Voorbeeld van het rekenmachine 6
3.5 A: Regendruppels In een weerkundig model worden vallende regendruppels gesimuleerd. Als programmeur wordt jou de opdracht gegeven om hiervoor een 2D model op te stellen. In dit model worden 50 regendruppels voorzien, elk met een diameter van 20 pixels. Elke regendruppel bevat volgende eigenschappen: de hoogte t.o.v. de grond (y), de snelheid waarmee de druppel naar beneden valt. Deze start met 0, en neemt toe met de valversnelling (v), de horizontale positie (x), deze wordt eenmalig ingesteld en verandert nooit, een eigenschap of deze druppel al dan niet actief is. Door een randomgenerator te gebruiken, kan men beslissen of een inactieve druppel getekend zal worden. Zolang een duppel niet getekend wordt (inactief), blijven de hoogte en de snelheid van de duppel op 0. Initialiseer deze waarden van zodra de druppel getekend mag worden. De druppel wordt dan ook als actief gezet. Met de randomgenerator kan dus enkel beslist worden of een druppel van inactief naar actief overgaat. Als randomgenerator kan het normale Random object gebruikt worden. Zolang de druppel getekend wordt (kijk na wanneer de druppel de grond raakt), wordt de druppel als actief beschouwd. Wanneer deze grond raakt wordt deze inactief. Gebruik een array van 50 druppels, en hanteer een minimale vensterbreedte van 1000 pixels (50 druppels bij 20 pixels per druppel). Figuur 3: Voorbeeldprogramma van de regendruppels. De regendruppels zijn hier wit. 3.6 A: Hexconverter Schrijf een programma dat toelaat oom omzettingen tussen verschillende getalformaten uit te voeren. De bewerkingen die gevraagd worden zijn: conversie van hexadecimaal formaat (string) naar integer, conversie van integer naar hexadecimaal (string) formaat, 7
conversie van integer naar binair (string) formaat, conversie van binair (string) formaat naar integer, conversie van integer naar octaal (string) formaat, conversie van octaal (string) naar integer formaat, conversie van binair naar hexadecimaal en omgekeerd, conversie van octaal naar hexadecimaal en omgekeerd, conversie van octaal naar binair en omgekeerd. Maak gebruik van een conversieklasse met static methoden. 3.7 E: Audio In een geluidsimulator worden golven gegenereerd. Deze worden typisch op een map uitgezet en het vervolg van de simulatie wordt dan gevolgd. In deze opgave zullen we een vereenvoudigde simulatie schrijven. In deze simulatie zullen we enkel sinusoïdale golven genereren. Een sinusgolf wordt gekenmerkt door de frequentie en de amplitude. Maak een klasse aan die de sinusgolf kan aanmaken en de vermelde eigenschappen bijhoudt. Als extra eigenschap wordt er ook bijgehouden of het object al dan niet actief is (golf aan of uit). De gebruiker kan een aantal golven ingeven, en deze worden dan één voor één op een panel geplot (enkel de actieve). In de akoestiek geldt ook het superpositiebeginsel. Zorg ervoor (via een methode in het object) dat je golven kunt optellen. Geef de gesommeerde golf ook weer. Hint: Voorzie voor het sommeren van golven een methode die toelaat om een array van waarden als argument op te nemen en hierbij de huidige waarden mee op te tellen. Deze methode retourneert een array van waarden. Geef dit door aan de verschillende golven. 3.8 E: Snake Snake is het spel waarbij je een slang bestuurt en de slang objecten moet opeten. Telkens de slang iets opeet wordt deze langer. De objecten die de slang moet opeten komen op random plaatsen op de panel. Hiervoor genereer je een random x en y coördinaat en teken je het object op die plaats. Wanneer de slang het object opeet wordt een nieuw object weergegeven. De slang wordt voorgesteld door vierkantjes. Elke keer de slang iets opeet, wordt een vierkantje toegevoegd. Schrijf hiervoor een klasse (vb: slangsegment) met velden Xpos en Ypos en voorzie hiervoor de nodige getters en setters. Maak een object aan telkens de slang langer wordt. Hou alle objecten bij in een lijst. 8
Voor de beweging van de slang wordt telkens één nieuw coördinaat berekend (enkel voor het eerste segment, afhankelijk van de richting). De rest van de coördinaten wordt gewoon doorgeschoven naar het volgende segment. Hint: De slang bestaat uit blokjes die als vierkantjes kunnen worden voorgesteld. De X en Y coördinaat van elk blokje mag gelijkgesteld worden aan de linkerbovenhoek van dat vierkantje. Verdeel de panel (coördinaten) in stukken die evengroot zijn als de grootte van één blokje van de slang. Hint: Maak van deze zijdelengte ook gebruik om elk op te eten voorwerp op een veelvoud hiervan uit te zetten. Detecteren wanneer de slang het voorwerp kan opeten, wordt dan gedaan door zowel de X en Y coördinaten van de kop van de slang te vergelijken met de X en Y coördinaten van het voorwerp. Indien deze overeenkomen, wordt het voorwerp opgegeten en neemt de slang met 1 vierkantje toe. Hint: Gebruik een enum om de richting van de slang bij te houden. Telkens een richtingspijl ingedrukt wordt, wordt deze enum aangepast. Gebruik deze enum om de positie van het voorste segment aan te passen. Hint: Maak van de slang ook een object. 3.9 X: Gravity In ons zonnestelsel bevinden zich een zeer groot aantal hemellichamen waaronder onze vertrouwde zon en enkele kometen. Afgezien van een aantal niet gemeenschappelijke eigenschappen, worden hemellichamen gekenmerkt door de massa, de grootte (diameter), de bewegingssnelheid, de kleur en de positie (2D). Maak een klasse aan dat deze eigenschappen van de hemellichaam bevat. In ons zonnestelsel worden alleen de zon en één komeet getekend. Teken beide hemellichamen door deze de gepaste eigenschappen te geven. Natuurlijk blijven hemellichamen niet stationair binnen het zonnestelsel evolueren. Deze bewegen. De beweging van de hemellichamen wordt voornamelijk bepaald door de huidige snelheid van het hemellichaam en de zwaartekracht dat deze ondervindt t.g.v. andere hemellichamen. De grootte van de zwaartekracht t.g.v. een ander hemellichaam wordt beschreven als: F = G m1 m 2 r 2 (1) waarbij F de grootte van de zwaartekracht is, m 1 de massa van hemellichaam 1 is, m 2 de massa van hemellichaam 2 en r de afstand tussen beide hemellichamen. Ga dus na hoe de afstand tussen beide hemellichamen berekend kan worden (maak hiervoor een functie aan). In deze opgave mag de zon statisch blijven, dus enkel de positie van de komeet verandert. De nieuwe positie en snelheid van de komeet worden als volgt bepaald: p komeet = p komeet + v komeet t + at2 2 (2) v komeet = v komeet + at (3) De zwaartekracht, snelheid en positie worden uitgedrukt in vectoren (dus X en Y). Het verband tussen het vectorieel verband en de numerieke waarden in formules 1, 2 en 3 wordt gegeven 9
door de hoek tussen de posities van de zon en de komeet. Gebruik een timer om het effect van de gravitatie op de komeet weer te geven. Teken ook de situatie. Hint: F = m a Figuur 4: Voorbeeld van 3 hemellichamen. Hier worden ook de snelheidsvector (groen), samen met de zwaartekracht (rood) dat ondervonden wordt door elk lichaam getekend. De pijlen hoeven niet getekend te worden. 10