Blog

Leren programmeren objectificeren

Voordat ik dit blog ben gaan schrijven heb ik een aantal van mijn trouwe blog lezers toegezegd dat ik in mijn onophoudende missie om te laten zien dat programmeren geen magie is (voor de woordgrap is het belangrijk dat je ons wie-zijn-wij filmpje even kijkt) een blog zou schrijven over APIs. Terwijl ik daar mee bezig ben en aan het kijken wat ik daar voor uit wil leggen loop ik tegen JSON aan, wat staat voor JavaScript Object Notation. JavaScript is al wel een heel aantal keer voorbij gekomen, maar objects heb ik nog niet echt uitgelegd. In eerste instantie wilde ik een kleine paragraaf er aan wijden, maar dat voelde wat karig. Het alternatief was om het te noemen en dan later toe te lichten, maar ik moet ook ooit nog een keer 3-waarde logica uitleggen en het was eigenlijk logischer om dat eerst te doen. De APIs komen volgende keer (of de keer daarop) maar vandaag: object georiënteerd programmeren.

Misschien dat je de term object georiënteerd programmeren of de afkorting OO/OOP wel eens voorbij hebt zien komen. Object georiënteerd programmeren is een manier van programmeren, andere vormen zijn bijvoorbeeld functioneel, logisch of declaratief. De code die ik jullie tot nu toe heb laten zien is allemaal declaratief; het is een opsomming van constructies. Bij OOP ga je uit van objecten. Stel je maakt een spelletje zeg monopolie, dan is eigenlijk alles wat je vast kan houden een object: het bord, het geld, de pionnen, de kanskaarten, de straten etc. Als voorbeeld ga ik de dobbelstenen nemen, vooral omdat die vrij universeel in een heleboel andere spellen gebruikt worden.

Omdat ik geloof dat je moet blijven proberen om programmeren een beetje onder de knie te krijgen ga ik de objecten als een functie implementeren, dat is misschien niet de manier waarop de meeste tutorials het uitleggen, maar het zorgt er voor dat je de script snippets die ik straks laat zien zo in je browser console kunt plakken en uit proberen. Bovendien kan ik daarmee in een later blog heel makkelijk JSON uitleggen, maar dat is voor later. Laten we een object gaan maken.

Voor het maken van een object moeten we eerst bedenken wat de eigenschappen van dat object zijn. Voor een standaard dobbelsteen is dat een kubus met dus een 6 tal zijdes, met op die zijdes een aantal ogen oplopend van 1 t/m 6. Ook is het zo dat de som van het aantal ogen van de twee zijdes die het verst van elkaar afliggen 7 is, maar daar gaan we ons in het voorbeeld geen zorgen over maken. Eerst gaan we het aantal zijdes toevoegen.

var dobbelsteen = {
  aantalZijdes: 6
}

Dat was nog niet heel ingewikkeld toch? Laten we ook nog de ogen toevoegen, dat is een lijstje, dus dat zetten we tussen blokhaken.

var dobbelsteen = {
  aantalZijdes: 6,
  ogen: [1, 2, 3, 4, 5, 6]
}

Als we dat in onze browser console gooien en we proberen vervolgens het 3de oog te laten zien ziet dat er zo uit:

var dobbelsteen = {
  aantalZijdes: 6,
  ogen: [1, 2, 3, 4, 5, 6]
}
dobbelsteen.ogen[2];
> 3

Dat komt een lijstje in JavaScript begint bij 0, dus als we het 3de element willen hebben moeten we het item uit het lijstje hebben met het nummertje 2. Nu hoor ik je denken, leuk, maar wat is hier nou het voordeel van boven:

var dobbelsteenZijdes = 6;
var dobbelsteenOgen = [1,2,3,4,5,6];

Goede vraag, ik had hem zelf kunnen stellen. Een voordeel is dat je de variabelen mooi groepeert en die groepering vervolgens weer gemakkelijk ergens anders kunt gebruiken. Ook geeft het je code een gestructureerde logica, alles is een object en heeft eigenschappen. Maar een object kan meer dan alleen variabelen groeperen. Hij ondersteunt naast eigenschappen ook acties en in JavaScript zijn acties functies. Dobbelstenen moeten rollen, dus laten we een functie maken om dat te ondersteunen.

var dobbelsteen = {
  aantalZijdes: 6,
  ogen: [1, 2, 3, 4, 5, 6],
  dobbel: function () {
    return this.ogen[Math.floor(Math.random() * this.aantalZijdes)]
  }
}

Nu kunnen we dobbelen door de functie aan te roepen als actie van de dobbelsteen:

dobbelsteen.dobbel();
> 4

Met monopolie heb je twee dobbelstenen en het aantal zetten dat je mag doen is het totaal van de twee dobbelstenen, dat is nu simpel te doen:

dobbelsteen.dobbel()+dobbelsteen.dobbel()
> 7
dobbelsteen.dobbel()+dobbelsteen.dobbel()
> 6

Bij de 7 gaat dit goed, bij 6 echter kan het zijn dat we dubbel hebben gegooid, namelijk 2x 3, als dat zo is mogen we nog een keer gooien, dus dat is wel belangrijk om te weten. Of een worp ‘dubbel’ is eigenlijk een eigenschap van beide dobbelstenen. Als beide dobbelstenen samen één eigenschap hebben, dan zijn ze eigenlijk samen voor ons ook  een object dat bestaat uit 2 dobbelsteen objecten. Dat ziet er zo uit:

var dobbelstenen = {
  aantalDobbelstenen: 2,
  dobbelstenen: [dobbelsteen, dobbelsteen]
}

Dat is wel heel vaak het woord dobbelsteen, en we mogen zelf de namen kiezen, dus laten we dit object worp noemen:

var worp = {
  aantalDobbelstenen: 2,
  dobbelstenen: [dobbelsteen, dobbelsteen]
}

De worp heeft dan natuurlijk ook een actie dobbel, waar in beide dobbelstenen worden gedobbeld:

var worp = {
  aantalDobbelstenen: 2,
  dobbelstenen: [dobbelsteen, dobbelsteen],
  dobbel: function () {
    return this.dobbelstenen[0].dobbel() + this.dobbelstenen[1].dobbel()
  }
}

Dit lost ons probleem nog niet op, maar we hebben nu de twee dobbelstenen samen, dus we kunnen nu kijken of er dubbel gegooid is, daarvoor voegen we een klein beetje extra logica toe:

var worp = {
  aantalDobbelstenen: 2,
  dobbelstenen: [dobbelsteen, dobbelsteen],
  dobbel: function () {
    let dobbel1 = this.dobbelstenen[0].dobbel();
    let dobbel2 = this.dobbelstenen[1].dobbel();
    let dubbelIndicator = ""
    if (dobbel1 == dobbel2) {
      dubbelIndicator = " dubbel!"
    }
    return dobbel1 + dobbel2 + dubbelIndicator
  }
}

Dan nog even testen of het werkt.

worp.dobbel()
> "6"
worp.dobbel()
> "11"
worp.dobbel()
> "8"
worp.dobbel()
> "4"
worp.dobbel()
> "12 dubbel!"

Aah ja daar is die, nou is het voor 12 natuurlijk altijd dubbel, maar we weten ook dat de 6 8 en 4 die we daarvoor hebben gedobbeld niet dubbel waren.

Nou zijn er ook dobbelstenen met een andere vorm en andere hoeveelheden ogen, in het spel D&D (Dungeons and Dragons) heb je verschillende dobbelstenen en daarmee bedoel ik dit soort dobbelstenen:

Een veelgebruikte is er één met 20 zijdes, die noem je d20 (dobbelsteen met 20 zijdes). We hebben nu het object dobbelsteen met 6 zijdes, maar we kunnen daar ook prima 20 zijdes van maken.

dobbelsteen.aantalZijdes = 20;
dobbelsteen.ogen = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20];

Omdat we nu het bestaande object dobbelsteen hebben aangepast is dat ook meteen aangepast in het worp opject, dus als we nu de worp dobbelen kunnen we veel hogere getallen krijgen:

worp.dobbel()
> "21"
worp.dobbel()
> "19"

Dat zijn objecten. Ergens in het begin zei ik dat dit waarschijnlijk niet de manier is waarop het in de meeste tutorials uitgelegd wordt. Wat ik nu heb laten zien is hoe je losse objecten aanmaakt door een variabele te vullen met JSON (JavaScript Object Notation.) Wat je meestal zult zien is dat er een model van een object wordt gemaakt, en dat je daar vervolgens versies van kan maken. Ik zal daar ook nog een voorbeeld van laten zien, maar daar ga ik iets sneller; ik heb het verzoek gekregen de blogs niet te lang te maken, en ik zit al weer op ruim 1000 woorden.

Wat we gaan doen is functie objecten maken, in plaats van JSON gebruiken we een functie om het object te defineren.

//standaard aantal zijdes is 6
function d(az = 6, o = []) {
  this.aantalZijdes = az;
  this.ogen = o;
  //als je alleen het aantal zijdes op geeft vullen we die met getallen
  if (o.length == 0) {
    for (let i = 1; i <= az; i++)
      o.push(i);
  }
  this.dobbel = function () {
    return this.ogen[Math.floor(Math.random() * this.aantalZijdes)]
  }
}

Nu kunnen we simpel zeggen:

var d20 = new d(20);

En nu is d20 een dobbelsteen met 20 zijdes. Maar we kunnen ook een kleuren dobbelsteen maken met:

var dkleur = new d(6,["rood", "geel","groen","paars","oranje","blauw"] );

Als je dan dobbelt krijg je één van die kleuren terug.

dkleur.dobbel()
> "blauw"

Dat kunnen we dan natuurlijk ook voor de worp doen:

function w(ds, aantal = 0) {
  //als er 1 dobbelsteen wordt meegegeven vul het lijstje met aantal stuks er van
  if (aantal > 0) {
    this.dobbelstenen = [];
    for (let i = 1; i <= aantal; i++)
      this.dobbelstenen.push(ds);
  } 
  //anders gebruik de opgegeven dobbelstenen
  else
    this.dobbelstenen = ds;
  this.dobbel = function (show = false) {
    let totaal = 0;
    let resultaat = ""
    for (d of this.dobbelstenen) {
      let ogen = d.dobbel()
      totaal += ogen;
      resultaat += ogen + "+";
    }
    resultaat = resultaat.substr(0, resultaat.length - 1);
    resultaat += "=" + totaal
    if (!show)
      resultaat = "" + totaal
    return resultaat;
  }
  this.dobbelShow = function () {
    return this.dobbel(true);
  }
}

In D&D kan je een spreuk doen die 8d8 aan schade doet (Je moet dan 8 keer met een dobbelsteen met 8 zijdes rollen en het totaal optellen, Dungeons and Dragons ga ik verder niet uitleggen hoor, dat moet je maar een keer bingen), als we dat in onze object georiënteerde functies willen doen kans dat nu zo:

var d8 = new d(8);
var w8x8 = new w(d8,8)
w8x8.dobbelShow()
> "3+1+8+8+7+3+7+6=43"
w8x8.dobbel()
> "30"

Dat zijn kort samengevat objecten. Ik heb het voorbeeld gegeven van dobbelstenen, maar deze techniek kan je voor vrijwel alles toepassen. Kleine tip: als je mensen of dieren objectificeert, zorg dan wel dat je dat alleen tijdens het programmeren doet, sommige dingen vertalen slecht naar de echte wereld.

Back-To-Top