Introduction à la POO

POO : Programmation Orientée Objet (ang. OOP : Object Oriented Programming)

Nous sommes maintenant bien familiarisés avec la notion d'objet :

objets fondamentaux : String, Number, Boolean,
objets du langage de base : Date, Math, Array,
objets du DOM : window, window.document, window.document.forms, etc.

On déclare une instance d'un objet (d'une classe, comme on dit en POO pure ; pour les purites, Javascript est seulement "orienté" objet) au moyen de l'opérateur new qui appelle le constructeur d'objet :

d = new Date() ;
a = new Array() ;

Nous allons maintenant découvrir comment il est possible de créer nos propres objets et leur attribuer des propriétés et des méthodes.

Constructeur d'objets : création de propriétés

En Javascript, il est possible de déclarer une instance de n'importe quel objet, pourvu que l'on crée pour cet objet un constructeur. Par exemple, pour représenter (on dit aussi "modéliser") une voiture, on peut créer une instance de l'objet Voiture, comme ci-dessous :

<body>
<script type="text/javascript">
<!--


v = new Voiture() ;

//-->
</script>
</body>

Dans ce script, Voiture() est le constructeur de l'objet Voiture. Ce constructeur doit être défini préalablement sous forme d'une fonction, comme ceci

<head>
<script type="text/javascript">
<!--


function Voiture() {
this.marque = "Renault" ;
this.modele = "Clio" ;
this.couleur = "noir" ;
}

//-->
</script>
<head>

Le constructeur prend la forme d'une fonction qui attribue à l'objet créé (représenté par la référence this) les propriétés désirées. Ces propriétés peuvent ensuite être utilisées tout-à-fait normalement en utilisant la syntaxe à point, par exemple, pour être imprimées :

<body>
<script type="text/javascript">
<!--


v1 = new Voiture() ;
v2 = new Voiture() ;
document.write(v1.marque+" " + v1.modele + " " + v1.couleur) ; document.write(v2.marque+" " + v2.modele + " " + v2.couleur) ;

//-->
</script>
</body>

Cette technique permet de mieux modéliser la réalité qu'en utilisant la programmation classique. Ainsi, il serait possible d'arriver au même résultat en utilisant 3 variables marque, modele, couleur, mais il serait difficile de faire apparaître l'existence d'une instance v de l'objet Voiture.

Le constructeur ci-dessus est capable de créer une seule classe de voiture : les Renault Clio noires. Il devient beaucoup plus utile s'il peut créer n'importe quelle voiture dont on lui fournit les caractéristiques. Celles-ci doivent être transmises en paramètres au constructeur qui les recopie à son tour dans les propriétés de l'instance :

<body>
<script type="text/javascript">
<!--


v1 = new Voiture("Renault", "Laguna", "bleu") ;
v2 = new Voiture("BMW", "318", "gris souris") ;
document.write(v1.marque+" " + v1.modele + " " + v1.couleur) ;
document.write(v2.marque+" " + v2.modele + " " + v2.couleur) ;

//-->
</script>
</body>

Voici la forme que prend alors le constructeur :

function Voiture(marque, modele, couleur ) {

this.marque = marque ;
this.modele = modele;
this.couleur = couleur ;

}

Les noms des arguments n'ont bien sûr pas d'importance. On obtient le même résultat avec la forme ci-dessous du constructeur :

function Voiture(x, y, z) {
this.marque = x ;
this.modele = y;
this.couleur = z ;
}

Puisque l'on peut construire une voiture, nous pouvons envisager de construire une flotte automobile.

v1 = new Voiture("Renault", "Laguna", "bleu") ;
v2 = new Voiture("BMW", "318", "gris souris") ;
v3 = new Voiture("VW", "Polo", "rouge") ;


f = new Fleet(v1, v2, v3) ;

 

Le constructeur Fleet() prend la forme ci-dessous :

 

function Fleet () {

n = arguments.length ;
this.vehicules = new Array(n) ;
for (i = 0 ; i < n ; i++) {

this.vehicules[i] = arguments[i] ;


} ;
}

 

L'objet arguments de l'objet function (Oui, il existe un objet function) contient la liste des arguments (les paramètres) transmis au constructeur. Comme nous en avons l'habitude, cet objet est un tableau (Array). La propriété length indique la longueur de ce tableau. Cela nous permet d'invoquer le constructeur avec un nombre variable de paramètres. Le constructeur commence par construire un tableau vehicules de longueur length et y range chacune des voitures transmises en arguments.

Pour afficher la marque du premier vehicule, on écrit :

v1 = new Voiture("Renault", "Laguna", "bleu") ;
v2 = new Voiture("BMW", "318", "gris souris") ;
v3 = new Voiture("VW", "Polo", "rouge") ;
f = new Fleet(v1, v2, v3) ;
document.write(f.vehicules[0].marque) ;

Pour afficher dans une table tous les véhicules du parc , on écrit :

document.write("<table>") ;

 

for (var i = 0 ; i < f.vehicules.length ; i++) {


document.write("<tr>") ;
document.write("<td>" + f.vehicules[i].marque+ "</td>") ;
document.write("<td>" + f.vehicules[i].modele+ "</td>") ;
document.write("<td>" + f.vehicules[i].couleur+ "</td>") ;
document.write("</tr>")
}

document.write("</table>") ;

Constructeur d'objet : création de méthodes

Comme tout objet, notre objet Fleet peut être doté de méthodes. Par exemple, pour lui ajouter une méthode affiche() on écrit :

function Fleet () {
n = arguments.length ;
this.vehicules = new Array(n) ;
for (i = 0 ; i < n ; i++) {

this.vehicules[i] = arguments[i] ;

} ;
this.affiche = mfAffiche ;
}

Remarquez bien l'absence de parenthèses à mfAffiche ci-dessus.

this.affiche est une méthode et on lui affecte le nom d'une fonction et non pas le résultat de cette fonction. C'est pour cette raison qu'il ne faut pas de parenthèses à mfAffiche.

Pour appeler la méthode, il suffit d'utiliser la syntaxe à point. Remarquez bien la présence des parenthèses lorsqu'on invoque la méthode.

f = new Fleet(v1, v2, v3, v4) ;
f.affiche() ;

 

Mais la fonction mfAffiche() doit être définie par ailleurs. Il suffit de reprendre le code utilisé supra et de l'utiliser dans une fonction. La question que chacun se pose alors est "comment cette fonction va-t-elle pouvoir accéder au tableau vehicules ?". La réponse est magique : tout simplement par la référence this.

function mfAffiche() {


document.write("<table>") ;

for (var i = 0 ; i < this.vehicules.length ; i++) {

document.write("<tr>");
document.write("<td>" + this.vehicules[i].marque+ "</td>") ;
document.write("<td>" + this.vehicules[i].modele+ "</td>") ;
document.write("<td>" + this.vehicules[i].couleur+ "</td>") ;
document.write("</tr>")
}

document.write("</table>")
}

 

Une classe Fleet évoluée

L'objet Fleet souffre d'un défaut majeur : il n'est pas possible de lui ajouter de nouveaux véhicules.

Idéalement, il faudrait pouvoir créer un objet Fleet vide, puis lui ajouter les voitures, comme ceci :

f = new Fleet() ;
f.ajoute("Renault", "Laguna", "bleu") ;
f.ajoute("BMW", "318", "gris souris") ;
f.ajoute("VW", "Polo", "rouge") ;
f.ajoute("VW", "Passat", "vert") ;
f.affiche() ;

 

Voyons ce que doit faire notre constructeur Fleet(). Il doit créer un tableau pour contenir les véhicules du parc. Nous ne connaissons pas a priori le nombre de vehicules, mais nous n'en avons pas besoin pour créer le tableau. Par contre, pour connaître à tout moment le nombre de véhicules, nous créons la propriété nbVehicules qui sera initialisée à 0. La classe Fleet doit ensuite disposer d'une méthode ajoute() qui reçoit en argument les paramètres marque, modele, voiture, ainsi que d'une méthode affiche() qui énumère tous les véhicules. Voici donc notre constructeur Fleet() :

function Fleet () {

this.nbVehicules = 0 ;
this.vehicules = new Array() ;
this.ajoute = mfAjoute ;
this.affiche = mfAffiche ;

}

La méthode ajoute() ajoute une nouvelle voiture au tableau vehicules. Elle doit donc à son tour appeler le constructeur Voiture() comme nous l'avons fait précédemment et en même temps incrémenter la propriété nbVehicules. La fonction mfAjoute() s'écrit donc :

function mfAjoute(marque, modele, couleur) {


v = new Voiture(marque, modele, couleur) ;
this.vehicules[this.nbVehicules++] = v ;

}

La fonction mfAffiche() reste inchangée ainsi que le constructeur Voiture().