Hoe groter software wordt, hoe tijdrovender het testen en onderhouden. Daarom wordt in de softwarewereld gezocht naar manieren om programma’s onderhoudbaar te maken. Een van de meer succesvolle manieren is het werken met objecten. Een team dat een Computer Game maakt over een hero (held) die tegen monsters vecht zal liefst op één plek willen programmeren wat de eigenschappen van de hero zijn en ook wat een monster is en wat je aan het monster kunt vragen.

Als er 2 monsters zijn worden er 2 objecten gemaakt,
als er 8 monsters zijn worden er 8 objecten gemaakt.
Elk van deze objecten representeert 1 monster.
De eigenschappen en het gedrag van een monster wordt geprogrammeerd in
een stuk van het programma dat we een Class
(klasse) noemen en dat (in dit voorbeeld)
de naam Monster krijgt.
Voorbeeld in C# (hoe je dit in Visual Studio kunt doen komt een stukje verder):
class Monster {
...
}
waarbij op de plaats van de puntjes de code voor deze class komt.
Voorbeeld in Java:
class Monster {
...
}
Voorbeeld in Swift:
class Monster {
...
}
Inderdaad, deze voorbeelden zijn hetzelfde.
Je zult merken dat er echt wel verschillen zijn hoe je in de ene of de andere taal een class noteert, maar in welke taal je ook zit:
welke classes je aanmaakt blijft hetzelfde!
In veel programmeertalen is afgesproken dat de naam van een `class` met een hoofdletter begint.
Software Engineers bedenken in het begin van een project
welke objecten er nodig zijn en daaruit volgt
welke classes er geprogrammeerd gaan worden.
Dit kun je grotendeels bedenken zonder te weten in welke taal
de software gebouwd gaat worden.
Je kunt dat enigszins vergelijken met het bouwen van een huis:
Waar de muren, ramen en deuren komen (de structuur) kun je tot zekere hoogte
bedenken en tekenen zonder te weten of het huis met bakstenen,
van beton of van hout gebouwd gaat worden.
Een object kan bepaalde eigenschappen hebben.
Zo zal elk Monster in eerste instantie helemaal gezond zijn.
Als de hero hem aanvalt zal het monster
moe worden of gewond raken en
uiteindelijk wellicht bezwijken.

Klik met rechtermuisknop op het project en kies Add Item,
kies daarna een class. Onderin het scherm kun je de gewenste
class name aangeven (file name is class name met
extensie .cs) en dan op de OK-knop.
In veel programmeertalen is het gebruikelijk om elke class in een eigen file
te programmeren.
In dit spel kunnen we dat realiseren
door het monster hitPoints te geven:
Voor een pas aangemaakt monster staat dit op 100,
bij verwondingen wordt dit gehele getal steeds kleiner,
bij 0 valt het monster verslagen neer.
Een waarde als hitPoints die elk object
van een bepaald type met zich meedraagt
noemen we een Field
We maken hiertoe in Monster een field levenspunten aan.
class Monster {
int hitPoints = 100;
}
Hiermee is bepaald dat elk monster hitPoints heeft. De waarde van dat getal kan per monster object verschillen: Monster 1 kan nog op 100 staan terwijl monster 2 misschien nog maar 13 over heeft.
De code die in een class staat wordt gedeeld met alle objecten
van die class (meestal zeggen we: alle objecten van dat type,
want een class is een manier om een type te definiëren).
Om een object van class Monster aan te maken:
C# of Java:
new Monster()
(we zeggen dan ook wel dat er gebruik gemaakt wordt van de new operator)
Hiermee wordt ergens in het geheugen een object
van type Monster aangemaakt, we hebben echter géén manier
om naar dat object te verwijzen (refereren).
Vergelijk het met een ballon met gas: zolang je
het touwtje hebt (de referentie naar de balon) kun je bij de ballon,
maar als je het touwtje loslaat kun je niet meer bij de ballon komen.
Zo’n referentie kunnen we opslaan in een Field
(ook wel een variabele genoemd)
en dat Field moet ergens in een class zitten:
We maken hiervoor een Game-object aan dat
de referenties naar alle heroes en monsters bevat.
De code van het Game object komt in de class Game te staan.

In class Hero is een Field
int numberDefeatedMonsters = 0;
aangemaakt. De held wil namelijk graag dat de hele wereld weet hoeveel
monsters er door hem/haar verslagen zijn.
De Class Game heeft referenties naar 1 hero en
2 monsters (monster 1 en monster 2) en aan het ervoor vermelde
type (dat zijn de class namen) kun je zien dat
de hero zich gedraagt zoals in class ‘Hero’ geprogrammeerd is,
terwijl de beide monsters zich gedragen volgens de code in class Monster.
public Game()
{
Hero hero = new Hero();
Monster monster1 = new Monster();
Monster monster2 = new Monster();
}
Onze hero staat te popelen om een monster te gaan aanvallen.
Hiervoor gaan we gedrag in de class Hero programmeren:
Dit wil zeggen dat je op een object van type Hero
een method kunt aanroepen die Attack heet.
Verder vertel je welk monster aangevallen wordt en
hoeveel schade (damage)
hierbij toegebracht wordt aan het monster (dus hoeveel er van de
hitPoints punten van het monster af gaan).
Als de method Attack op een Held object aangeroepen wordt
wordt de code van die methode uitgevoerd.
De held roept dan van het tussen haakjes genoemde monster de method LooseHealth
aan. Nu gaan we coderen hoe die method
er uit kan zien: daartoe programmeren we de method
Attack in de class Hero
void Attack(Monster monster, int damage)
{
monster.LooseHealth(damage);
}
ofwel: als op een object van type Hero (want in die class staat deze code)
de method Attack wordt aangeroepen (met als parameters tussen haakjes
aangegeven welk monster en hoeveel damage)
roept die de method LooseHealth
aan van het aangegeven monster. De binnengekomen info
over hoeveelheid damage wordt doorgegeven.
In de method worden 2 zogenaamde parameters gebruikt, namelijk
monster van het type Monster en
damage van het type int (tussen haakjes te vinden na
de methode naam).
Het woord void wil zeggen dat er geen waarde wordt teruggegeven door de methode,
Er kan ook in plaats van void een zogenaamd return type staan dat aangeeft
wat voor soort waarde er terug gegeven wordt.
In class Monster moet vervolgens de method LooseHealth
gecodeerd worden:
void LooseHealth(int damage)
{
this.hitPoints = this.hitPoints - damage;
}
Uitleg:
this.hitPoints - damage.- damage’ zorgt dat de meegegeven waarde van de parameter hier vanaf getrokken wordt.Net zoals we bij een methode aanvullende informatie mee kunnen
geven in de vorm van parameters kunnen we dat bij het aanmaken
van een nieuw object ook. Hiertoe gebruiken we een constructor:
Een constructor ziet er ongeveer uit als een methode:
Monster(int initialHealth)
{
this.hitPoints = initialHealth;
}
Een constructor herken je alsvolgt:
return-type (of void) vermeld.class.Je kunt natuurlijk de code hierboven zelf intypen (tussen de accolades van de class)
maar als je op die plek intypt ctor en dan 2x op tab drukt
doet Visual Studio een deel van het werk voor je.
Als we nu new Monster(125) aanroepen vanuit code wordt er een object
van type Monster geconstrueerd en daarvoor staat na constructie
de hitPoints-waarde op het meegegeven getal, 125 dus in dit geval.
Bij een constructor kunnen (net als bij een normale methode) ook
meerdere parameters meegegeven worden.
We hebben nu een basis neergezet voor een spel waarin een hero monsters kan aanvallen.
Later wordt nog uitgelegd waarom, maar onthoudt vast dat we elk Field private maken.
Methods en classes mogen public zijn.
Voor de volledigheid volgt nu de code van de classes zoals die tot hier beschreven is.
Allereerst de class Game
namespace HereComeTheMonsters
{
public class Game
{
public Game()
{
Hero hero = new Hero();
Monster monster1 = new Monster(125);
Monster monster2 = new Monster(100);
}
}
}
dan class Hero
namespace HereComeTheMonsters
{
public class Hero
{
public Hero()
{
}
public void Attack(Monster monster, int damage)
{
monster.LooseHealth(damage);
}
}
}
en tot slot class Monster
namespace HereComeTheMonsters
{
public class Monster
{
private int hitPoints = 100;
public Monster(int initialHealth)
{
this.hitPoints = initialHealth;
}
public void LooseHealth(int damage)
{
this.hitPoints = this.hitPoints - damage;
}
}
}