Programmation orientée objet par prototype avec jQuery


précédentsommairesuivant

I. Introduction

I-A. Introduction

Je résumerai le titre par le vocable POOPJ, prononcez "pop j".

Je suis persuadé que jQuery est un outil fantastique pour la manipulation du DOM, mais cela ne représente que 80 % de la programmation en JavaScript. Pour le solde, la Programmation orientée objet (POO) répond à l'essentiel des besoins. Faut-il pour autant recourir obligatoirement à une autre bibliothèque JavaScript comme Dojo ? Non, je crois qu'il suffit d'un outil léger, permettant l'héritage simple, c'est pourquoi j'ai créé POOPJ.

$.dvjhClass est l'outil qui permet d'écrire du code poopj. C'est un objet JSON comprenant trois méthodes : _create(), _base() et toString(). L'outil permet de réunir dans un même corpus la fonction d'initialisation et son prototype.

(1) $.dvjhClass simplifie l'usage de la méthode d'héritage simple décrite par Thierry Templier au chapitre 1.4 de la deuxième partie de son tutoriel : "Programmation orientée objet avec le langage JavaScript".

Cette technique d'héritage ne permet pas le polymorphisme (objX instanceof objY), mais c'est la plus appropriée dans la plupart des cas. Si le polymorphisme et l'héritage multiple vous manquent, le tutoriel de Thierry Templier décrit d'autres techniques d'héritage.

Le code poopj n'est qu'un emballage qui rend l'Orienté Objet par Prototype (OOP) plus séduisant, et facilite son utilisation. Mais tous les avantages du OOP, tous ses travers et toutes ses insuffisances sont toujours là.

Nous examinerons d'abord, avec l'aide de plusieurs exemples simples, comment générer du code poopj avec §.dvjhClass._create(). Nous regarderons ensuite, très succinctement, le code de l'objet $.dvhClass qui ne présente aucune difficulté particulière pour un initié.

J'ai écrit l'outil en jQuery, mais vous pouvez utiliser ou publier une version purement JavaScript dans le respect des termes de la licence.

I-B. Quelques rappels sur la POO

La notion de classe n'existe pas en JavaScript, mais le besoin de qualifier la chose existant bien, je désigne le code généré par $.dvjhClass._create() sous le vocable "fonction classe".

(2) Je cite Grady Booch : "La programmation orientée objet est une méthode d'implémentation dans laquelle des programmes sont organisés comme des ensembles coopérants d'objets, chacun représentant une instance d'une certaine classe, et toutes les classes sont des membres d'une hiérarchie de classes unifiées par des relations d'héritage."

En POO, les mots instance et objet sont synonymes.

L'héritage simple représente une hiérarchie d'abstractions, dans laquelle une "fonction classe" fille hérite d'une "fonction classe" mère. Typiquement, une "fonction classe" fille enrichit ou redéfinit la structure et le comportement de la "fonction classe" mère. (Cette phrase a été adaptée à mes besoins, l'originale est de Grady Booch (2).)

On doit distinguer trois sortes de relation entre les objets. La relation "est un" qui correspond à l'héritage, la relation "à un" qui correspond à un composant de l'objet et la relation "utilise un" qui correspond à un autre objet. Exemple : "Médor est un chien", "Médor à une queue" et "Médor utilise un collier".

Choisir entre les relations "à un" et "utilise un" dépend aussi du contexte de votre application. Exemple : "L'avion à un moteur" et "L'avion utilise un moteur". Dans l'absolu, il s'agit d'une relation "utilise un" mais si votre application s'intéresse surtout à la navigation aérienne, il n'est pas utile de développer une hiérarchie de classes pour décrire les moteurs d'avions.

(3) Il existe des règles à suivre pour obtenir un code POO de qualité. Mais, sans le support des mécanismes intégrés dans un véritable langage POO, elles peuvent paraître impossibles à satisfaire. Détrompez-vous, même en poopj, il est tout à fait possible d'appliquer une grande partie des règles de bases dans le but d'obtenir une bonne conception orientée objet.

Une "fonction classe" doit avoir une responsabilité unique. Elle ne doit regrouper que les fonctionnalités nécessaires à la réalisation d'un seul but.

Si le but à atteindre est complexe, construisez une hiérarchie de classes.

Toutes les "fonctions classes" d'une hiérarchie doivent offrir une interface commune. Dans cette interface, la dénomination et la signature (nombre et ordre des paramètres) des accesseurs, des mutateurs et des méthodes doivent être identiques.

Une "fonction classe" doit être conçue de telle sorte qu'elle puisse intégrer une nouvelle méthode et qu'elle puisse devenir la "fonction classe" mère d'une hiérarchie de "fonctions classes" filles sans qu'il soit nécessaire de modifier le code existant.

Une "fonction classe" mère peut-être abstraite. C'est même souvent une nécessité, car l'implémentation d'une méthode peut dépendre du contexte d'une "fonction classe" fille.

Une "fonction classe" ne doit pas tester (instanceof) l'objet qu'elle utilise, car cet objet doit pouvoir être une instance de n'importe quelle "fonction classe" d'une hiérarchie de "fonctions classes". Bien entendu, cela n'est possible que si toutes les "fonctions classes" d'une hiérarchie possèdent une interface commune.

L'état d'un objet est défini par la valeur de ses attributs, on dit qu'un objet change d'état lorsque l'on modifie la valeur d'un attribut de l'objet. Avant et après chaque changement d'état, on doit s'assurer, par des tests, que l'objet est toujours dans un état cohérent.

Une "fonction classe" fille ne doit jamais assouplir les contraintes imposées par sa "fonction classe" mère.

Dans un système de "fonctions classes" collaborant entre elles dans un même but, il peut sembler logique de trouver des dépendances entre les "fonctions classes". Mais pour des raisons de réutilisabilité et de maintenance du code, vous devez réduire ces dépendances au minimum. Pensez à séparer les couches métier, interface utilisateur et contrôle (M.V.C.). Même en JavaScript on peut satisfaire largement à cette règle en utilisant les événements.

Le code poopj, comme n'importe quel code JavaScript, doit être placé dans un fichier séparé.

Du point de vue de la conception et de la maintenance, ne placez jamais plusieurs "fonctions classes" sans rapport entre elles dans le même fichier.

Du point de vue de l'utilisateur, dans le cas d'un système de "fonctions classes" collaborant entre elles dans un même but ou d'une hiérarchie de "fonctions classes", livrez un seul fichier compressé (minified), en POO on parle de module distinct.

I-C. Les prérequis

Une bonne maîtrise des bases : CSS, HTML, JavaScript, et la notation JSON.

Les langages véritablement conçus pour la XOO (X pour analyse, conception et programmation. C++, Java, C#, etc.), n'en requièrent pas moins des programmeurs rigoureux, méticuleux et soigneux. JavaScript ne possédant aucun des mécanismes évolués et des garde-fous des véritables langages XOO, le codage et l'utilisation du poopj ne reposent que sur les épaules des programmeurs rigoureux, méticuleux et soigneux.

Si le programmeur qui a conçu les "fonctions classes" est celui qui les utilise, ou si le programmeur qui les utilise a les mêmes qualités, tout va bien.

Aux autres, aux amateurs de la bidouille, "du truc qui", aux amateurs des amas de codes jetés au hasard sans ordre ni méthode, aux oublieux des points virgules et en notation JSON des virgules, je prédis les pires catastrophes.

En bref, si vous codez comme un cochon le résultat sera porcin !

C'est également une des raisons pour laquelle j'ai écrit l'outil en jQuery, car les bons programmeurs jQuery ont nécessairement acquis une partie des qualités requises.

I-D. Utilité de l'héritage

(4) Voici, sortit de son contexte et dans une traduction approximative, ce qu'en pense Douglas Crockford : "Je n'ai jamais trouvé nécessaire d'utiliser l'héritage. L'idée est importante, mais elle semble être inutile en JavaScript. Je considère aujourd'hui mes premières tentatives pour intégrer l'héritage en JavaScript comme une erreur."

La complexification des codes JavaScript allant croissant, j'espère que les principes de rigueur, d'ordre et de méthode s'appliqueront bientôt au JavaScript comme ils se sont appliqués, avec succès, dans d'autres langages. Je crois que l'orienté objet par prototype (OOP) est un outil qui peut être utilisé dans ce but. Par l'expérience acquise en C++, je me vois mal utiliser la programmation orientée objet (POO) en étant privé de l'héritage simple.


précédentsommairesuivant
Conception orientée objets et applications par Grady Booch, Addison-Wesley, 1992.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+