Affichage des articles dont le libellé est pattern. Afficher tous les articles
Affichage des articles dont le libellé est pattern. Afficher tous les articles
Speudoclassical subclass
voici comment créer des sous classes en JavaScript.
Nous allons tenter de comprendre ce code.
Recopie
L'idée est simple, nous voulons écrire qu'un taxi "ressemble" à une voiture.Pourquoi ne pas écrire le code suivant.
L'idée est simple, un taxi a les mêmes propriétés qu'une voiture donc recopions simplement ces propriétés dans le constructeur.
Si l'idée semble ici séduisante, il faut penser que le nombre de propriétés à recopier ainsi peut être important et qu'un cas de modification d'une propriété, nous aurons à répéter cette modification en deux endroits. C'est bien pour cette raison que nous voulons éviter la recopie.
instancier Car
Pourquoi ne pas créer une instance de Car dans le constructeur.
Cette solution pose un certains nombre de problèmes.
Coté mémoire, nous créons une instance de Car à chaque fois que nous appellerons la fonction Taxi. Mais, en appelant new Car() dans le constructeur de cette façon, this dans le constructeur Car sera une nouvelle instance de Car et non de Taxi.
Rappelons nous que le langage en interne crée à chaque appel de new un objet this.
Mais, il n'y a pas de lien (mis à part le nom) entre ces deux objets this. Il y a bien deux objets distincts.
Il serait tentant d'écrire le code suivant. Mais, l’interpréteur du langage ne le permet pas et de toute façon il y aurait encore deux objets this.
Appel de la fonction
Pourquoi ne pas appeler simplement la fonction Car dans le constructeur. Encore une fois, la réponse est simple, l'objet this dans car ne représente pas une instance de Taxi mais l'objet global. Puisque la fonction est simplement invoquée dans le contexte global.Finalement, il suffirait de passer à cette fonction Car le this instance de taxi.
La solution utilise donc l'appel à la fonction call.
Il est parfois difficile d'appréhender son utilisation mais c'est en fait assez simple. Elle a pour rôle de faire correspondre les deux this qui au départ représente deux objets différents !
Une bonne explication est donnée sur la vidéo 11'30
Ainsi c'est le this de Taxi auquel on ajoutera une propriété pos. Il n'y aura donc aucun objet supplémentaire crée ni de recopie de propriétés.
Superclass et Subclass
Reprenons l'exemple de la functional Class.
Un problème classique est de définir des catégories de Voiture ayant des spécificités bien particulières.
Il faut a tout pris éviter de recopier le code comme le montre la figure suivante.
Il est clair que nous devons limiter la recopie de code commun. Par exemple la fonction move est dupliquée.
Nous allons définir une fonction (la super Fonction) qui regroupe le code commun. Nous créons ensuite d'autres fonction (les sous Fonction) qui décorent la super fonction. Mais, nous pouvons utiliser le mot classe à la place de fonction. Puisque la super classe a pour rôle de générer un grand nombre d'objets.
Un problème classique est de définir des catégories de Voiture ayant des spécificités bien particulières.
Il faut a tout pris éviter de recopier le code comme le montre la figure suivante.
Nous allons définir une fonction (la super Fonction) qui regroupe le code commun. Nous créons ensuite d'autres fonction (les sous Fonction) qui décorent la super fonction. Mais, nous pouvons utiliser le mot classe à la place de fonction. Puisque la super classe a pour rôle de générer un grand nombre d'objets.
Speudoclassical pattern
Revenons un instant sur le code de prototype class.
Nous voyons que chaque fois que nous voulons définir une fonction class, il faut créer un objet avec Object.create et le retourner.
Modifions le code précédant en introduisant this à la place de obj.
Et finalement puisque nous devons pour chaque class créer et retourner cette objet pourquoi ne pas l'intégrer directement dans le Langage et ainsi ne plus l'écrire dans le code. Pour valider ce type d'écriture (pour ne pas le confondre avec un autre type d'objet à modifier) il suffira d'appeler la fonction avec l'opérateur new.
Finalement, nous écrirons
Examinons une dernière fois ce code
En Partie 1, nous spécifions les parties spécifiques de chaque objet. Ces différences seront écrire à l'intérieur du constructeur.
En partie 2, nous aurons le code commun à partager entre tous les objets instanciés de la classe. Ces similarités seront stockées dans l'objet prototype de la classe.
Nous voyons que chaque fois que nous voulons définir une fonction class, il faut créer un objet avec Object.create et le retourner.
Modifions le code précédant en introduisant this à la place de obj.
Et finalement puisque nous devons pour chaque class créer et retourner cette objet pourquoi ne pas l'intégrer directement dans le Langage et ainsi ne plus l'écrire dans le code. Pour valider ce type d'écriture (pour ne pas le confondre avec un autre type d'objet à modifier) il suffira d'appeler la fonction avec l'opérateur new.
Finalement, nous écrirons
Examinons une dernière fois ce code
En Partie 1, nous spécifions les parties spécifiques de chaque objet. Ces différences seront écrire à l'intérieur du constructeur.
En partie 2, nous aurons le code commun à partager entre tous les objets instanciés de la classe. Ces similarités seront stockées dans l'objet prototype de la classe.
Prototype Class
La fonction Car, crée un objet copie les propriétés et retourne un objet.
Nous avons vue la différences entre la fonction extend et l'utilisation de object.create.
Nous allons utiliser cette délégation pour transformer notre code. Il suffit de remplacer avantageusement extend par Objet.create.
Functional Classes
Nous allons voir encore une fois, l'importance des fonctions dans le langage JavaScript et comment elle peuvent créer la base des classes.
Dans l'article du pattern décoration, nous avons vu comment une fonction peut augmenter (décorer) un objet existant.
Reprenons cet exemple :
A noter l'erreur de code loc = pos car la fonction carlike.
Dans l'article du pattern décoration, nous avons vu comment une fonction peut augmenter (décorer) un objet existant.
Reprenons cet exemple :
A noter l'erreur de code loc = pos car la fonction carlike.
La fonction carlike décore l'objet obj qui lui est passé en paramètre.
Nous allons renommer et modifier la fonction pour qu'elle génère les objets.
Le paramètre obj est remplacé par une déclaration de variable locale var obj = {...}.
A l'inverse de la fonction de décoration qui modifie un objet existant, la fonction Car crée ici l'objet obj et le retournera.
Notez la convention d'écriture de cette fonction : Le nom commence par une Majuscule.
Nous venons de définir ce que l'on appelle un constructeur. L'appel de cette fonction, une instanciation, retourne un objet de type Car. L'objet aCar est une instance. Les objets générés possèdent une propriété pos et une fonction move.
Nous avons déjà vu dans l'article pattern décoration que chaque objet possède sa propre fonction move. En sortant la fonction du constructeur, chaque objet va pointer sur la fonction move ce qui évite la duplication coûteuse en mémoire.
En sortant la fonction move du constructeur, nous n'avons pas conservé la closure et nous remplaçons obj par this. This sera l'objet placé à gauche de l'appel de la fonction. lorsque nous écrirons bcar.move() this sera lié à bcar.
Amélirations
Nous devons améliorer notre écriture, en effet, considérons que nous avons une vingtaine de fonctions identiques à move à écrire, ces fonctions apparaîtrons à deux endroits.
Nous regroupons les fonctions dans un objet methods. L'ajout d'une nouvelle fonction en ligne 12 ne modifie en rien (ligne 4) le constructeur Car.
Mais, en lisant le code, nous remarquons que l'objet methods n'est en rien lié à Car. Ainsi, pour améliorer la lisibilité, nous ajoutons methods comme propriété de la fonction Car. Ce qui évite en plus la création d'une variable globale methods.
Rappel : une fonction est un objet, un objet peut avoir des propriétés et méthodes. Il en est de même pour les fonction ! Une différence est que les fonctions peuvent être appelées.
Dans cette article, nous avons vue comment une fonction peut être considérée comme une classe. Dans d'autres articles, nous introduirons des amélioration de performance avec la chaîne de prototype : un des fondement de JS.
Annexe :
Pour la fonction extend(obj1,obj2), on pourra trouver des exemples de code sur le web.
Dans la bibliothèque jquery
L'idée générale est recopier chaque propriété de l'objet2 dans l'objet1.
var __slice = [].slice;
function extend () {
var consumer = arguments[0],
providers = __slice.call(arguments, 1),
key,
i,
provider;
for (i = 0; i < providers.length; ++i) {
provider = providers[i];
for (key in provider) { // pour toutes les methodes et propriétés
if (provider.hasOwnProperty(key)) { //oublions la chaîne de prototype
consumer[key] = provider[key]; // création d'une prop key et recopie
};
};
};
return consumer;
};
extend(sam, person);
sam.rename
Decorated pattern
Objectif
l'objectif de cet article est d'améliorer la qualité du code et d'introduire des notions de "design pattern".En particulier, nous introduirons le pattern "decorated".
Code de base
Nous allons écrire un programme initial.Ce programme modélise un ensemble de voitures.
Chaque voiture est représentée par sa position.
Voici le code qui déclare un objet littéral et l'affecte à une variable.
myCar est une variable globale qui "symbolise" la voiture.
La mémoire physique.
Voici une représentation sous forme de schéma.![]() |
Représentation de l'objet{pos:1} |
En mémoire la voiture dispose d'une case mémoire nommée pos pour stoker la position de la voiture sur un axe. L'objet {} possède une propriété pos qui pointe sur un objet représenté lui même par l'objet {1}.
Mais, pour manipuler simplement l'objet ma voiture qui se trouve stockée en mémoire physique de mon ordinateur, mon programme utilise la variable myCar. On dit que myCar pointe sur l'objet ma voiture.
Ajoutons une deuxième voiture et déplaçons les voitures
Nous allons tenter d'améliorer ce code !
Création d'une bibliothèque
Nous allons progressivement introduire au sein d'une bibliothèque des améliorations.
Définition d'une fonction :
A droite : Amélioration du code, création d'une bibliothèque. |
Nous améliorons notre code par un appel à la fonction.
La fonction move va regrouper les différentes actions communes à l'ensemble des voitures.
La fonction move va regrouper les différentes actions communes à l'ensemble des voitures.
Nous déclarons une variable globale move
qui pointe sur un objet fonction.
qui pointe sur un objet fonction.
Côté code, nous appelons la fonction move.
Remarque :
mycar.pos++ est remplacé par move(mycar)
L'amélioration n'apparaît pas clairement dans le fichier index.js.
L'intérêt de l'utilisation d'une fonction deviendra évident dans le cas d'un code plus complexe.
L'intérêt de l'utilisation d'une fonction deviendra évident dans le cas d'un code plus complexe.
Intérêt 1: éviter la recopie du code.
Voici un exemple qui montre l'intérêt de factoriser un grand nombre de lignes de code.
intérêt principal : modification du corps de la fonction.
En cas de modification, les changements seront localisés à un seul endroit.
Design pattern.
Pourquoi ne pas utiliser la technique précédente en écrivant une fonction de création des voitures ? Nous allons ainsi factoriser la création d'objets similaires.
Nous allons découvrir ainsi un "design pattern" très utile. Decorator Functions
Le corps de la fonction doit permettre de modifier des objets pour les faire "ressembler" à des voitures !
On parle de décoration. Comme c'est jolie !
Nous donnons le corps de la fonction. Notez bien que pour un cas réel le corps de la fonction serait plus important et l'intérêt de ne pas répéter le code serait évident.
this !
Modifions maintenant la fonction move pour faire apparaître un terme très employé this.Nous verrons que l'idée sera de ne plus utiliser une variable comme argument de la fonction move.
Dans la fonction move, this sera lié à l’objet qui est à gauche du point dans l'appel.
Par exemple this est lié, grâce au mécanisme de Javascript à l'objet mycar dans l'appel mycar.move().
Ainsi à l'appel de move( ), on fait correspondre les paramètres aux variables passées (il n'y en a pas ici) et à l'appel du point mycar[.]move() on fait correspondre this à l'objet mycar qui est à gauche du point.
Notez que obj.move pointe sur la fonction, il n'y a donc en mémoire qu'une seule fonction.
Attention au comportement de l'appel de la fonction move() seule. This serait lié à l'objet global windows. Le comportement ne serait surement pas celui attendu.
Encapsulation
Il semble intéressant d'intégrer la fonction move dans la fonction carlike.La lecture du code est plus clair et regrouper au sein d'une même fonction.
Mémoire
Rappels :
var makeObj = function () {
return {};
}
var a = makeObj();
var b = makeObj();
var c = a;
(a === b) // false, a et b sont comme des jumeaux mais aussi des personnes différentes
(a === c) // true
Remarque : les résultats de comparaison sont les mêmes si la fonction retourne une fonction à la place d'un objet.
La conséquence principale est donc la duplication du code de la fonction move (et donc de toutes les fonctions) pour chaque création d'objet.
Revenons une dernière fois au code. Un des avantage à inclure le code de la fonction move à l’intérieur de la fonction carlike et que nous pouvons nous servir de la closure.
Grace à la closure, après avoir exécuté la fonction carlike, la fonction move aura encore accès à la variable obj qui est passé en argument de carlike.
Comparer le code initial à ce code :
Inscription à :
Articles (Atom)