9.2. Objectes
A mesura que els nostres programes van creixent en complexitat, hem vist que sol ser convenient encapsular parts del codi en funcions o utilitzar variables per evitar redundàncies. Amb la introducció d’objectes en el nostre codi farem un pas més enllà i ens endinsarem en la programació orientada a objectes (OPP, object-oriented programming), un paradigma de programació en el qual començarem a pensar en els nostres programes com en petites estructures que es combinen per crear altres estructures més complexes. Sempre serà millor crear i mantenir estructures modulars més petites de codi que intentar escriure un programa monolític amb totes les funcionalitats.
Els objectes no deixen de ser una manera de vincular variables i funcions en una petita estructura. Com que ja sabem treballar tant amb variables com amb funcions, els objectes no seran més que una manera més convenient i estructurada de combinar el que ja sabem fer.
Propietats i mètodes
Aquestes variables i funcions que vinculem, quan parlem d’objectes, les anomenarem propietats i mètodes. El seu funcionament és completament el mateix que el de les variables i funcions que ja coneixem, però quan estiguin associades a un objecte ens referirem a aquestes com a propietats i mètodes.
D’aquesta manera, un objecte no és més que un conjunt de valors (propietats) associats entre si amb una sèrie d’accions i comportaments (mètodes).
Posem com a exemple que volem crear un paisatge al nostre sketch. Si seguim la lògica de la programació orientada a objectes, podríem pensar en el paisatge final com una estructura complexa composta d’altres estructures més petites (flors, arbres, cel, núvols…), i cadascuna d’aquestes estructures més petites podria ser un objecte.
Si triem un d’aquests objectes, la flor, per exemple, li podríem donar una sèrie de propietats: posició, mida i nombre de pètals. També algun comportament: créixer i que es mostri. Per tant, haurem de comptar amb les variables i funcions següents:
let posX, posY; let size; let numPetals; function grow(){} function display(){}
Classes i objectes
Cada flor individual podrà tenir diferent mida, posició o nombre de pètals, però totes les flors respondran sempre a aquesta mateixa estructura de propietats i mètodes. A aquesta estructura o plantilla de flor l’anomenem classe i a cadascuna de les flors individuals que creem a partir de la plantilla l’anomenarem objecte. Per tant, tindrem una classe flor amb la qual crearem diferents objectes flor. Vegem ara com crear una classe en P5.
El primer que hem de fer és utilitzar la paraula clau class seguida del nom de la nostra classe, que per convenció posarem en majúscula.
class Flower { // La nostra classe (plantilla) per crear flors }
A continuació, crearem dins de la classe el seu constructor, que defineix la forma en la qual més endavant crearem els nostres objectes. En el constructor definim quins paràmetres necessitarem donar al nostre objecte flor per a la seva creació i la seva relació amb les propietats que definim.
// De la mateixa manera que per crear un cercle tenim: // circle(posX, posY,) // Per crear la nostra flor volem una cosa així: // Flower(posX, posY, numPetals);
De manera que el nostre constructor haurà de ser una cosa similar al següent:
class Flower { constructor(posX, posY, numPetals) { } }
I dins del constructor establim la relació entre aquests paràmetres i les propietats de la nostra classe:
class Flower { constructor(posX, posY, numPetals) { this.posX = posX; this.posY = posY; this.numPetals = numPetals; } }
Dins de la classe estem creant i accedint a les seves propietats a través de la paraula clau this. D’aquesta manera, diem al programa que no són unes variables qualssevol, sinó que es tracta de propietats relatives a aquesta (this) classe. A continuació, els assignem valors que els passem com a paràmetre. Primerament, aquest codi pot semblar una cosa confusa, ja que els noms dels paràmetres i de les propietats són els mateixos, encara que no té per què ser així. Per fer el codi més comprensible (sobretot quan creem les nostres primeres classes), pot resultar convenient que, per exemple, als paràmetres els afegim algun prefix per aclarir-nos:
class Flower { constructor(_posX, _posY, _numPetals) { this.posX = _posX; this.posY = _posY; this.numPetals = _numPetals; } }
O també així:
class Flower { constructor(pPosX, pPosY, pNumPetals) { this.posX = pPosX; this.posY = pPosY; this.numPetals = pNumPetals; } }
En aquest cas, totes les propietats que hem definit dins del constructor estan associades a paràmetres que li passem, però no ha de ser així. Podem tenir propietats que definim directament:
class Flower { constructor(pPosX, pPosY, pNumPetals) { this.posX = pPosX; this.posY = pPosY; this.numPetals = pNumPetals; this.size = 20; this.flowerColor = “lightblue”; } }
Després d’haver definit el constructor de la nostra classe, mitjançant el qual crearem els objectes, podem definir mètodes de la classe. Per exemple, podríem tenir un mètode per fer créixer la flor:
class Flower { constructor(pPosX, pPosY, pNumPetals) { this.posX = pPosX; this.posY = pPosY; this.size = 20; this.numPetals = pNumPetals; this.flowerColor = "lightblue"; } grow() { this.size *= 1.01; } }
D’aquesta manera, cada vegada que cridem al mètode grow(), la mida de la flor augmentarà un 1 %. Si volem visualitzar la flor al nostre sketch, haurem de crear un altre mètode que s’encarregui de dibuixar-la utilitzant les seves propietats:
class Flower { constructor(pPosX, pPosY, pNumPetals) { this.posX = pPosX; this.posY = pPosY; this.size = 20; this.numPetals = pNumPetals; this.flowerColor = “lightblue”; } grow() { this.size *= 1.1; } display() { for(let i = 0; i < this.numPetals; i++) { noStroke(); fill(this.flowerColor); let angle = 2 * PI / this.numPetals * i; circle(this.posX + cos(angle) * this.size, this.posY + sin(angle) * this.size, this.size); } fill(250); circle(this.posX, this.posY, this.size * 1.5); } }
Aquí veiem com accedim a les propietats de la classe usant this per utilitzar-les a l’hora de dibuixar la flor. Per dibuixar els pètals, estem utilitzant un bucle amb el qual dibuixem cada pètal en el seu angle corresponent dividint 360° (2 × PI) entre el nombre de pètals i multiplicant-lo pel número del pètal en el qual ens trobem.
Ja tenim definida la nostra classe, amb les seves propietats i els seus mètodes. El que hem de fer ara és crear algun objecte amb aquesta «plantilla» que hem creat.
Per a això, la sintaxi és la següent:
function setup(){ createCanvas(400, 400); let flower = new Flower(width * 0.5, height * 0.5, 8); }
Usem la paraula clau new per definir que estem creant un objecte nou de la classe Flower i, a continuació, entre parèntesis li passem els paràmetres necessaris per a la seva creació. En aquest cas, volem la flor centrada en el canvas i amb vuit pètals.
Com amb la resta de les variables, si volem accedir a les seves propietats o cridar als seus mètodes més endavant, és bona pràctica que declarem la variable al principi del codi perquè hi puguem accedir tant des del setup() com des del draw(). Vegem el procés sencer de definició de la classe i creació d’un objecte basat en la classe:
Font: elaboració pròpia.