Maison  >  Article  >  interface Web  >  Explication détaillée des caractéristiques et exemples d'utilisation du modèle de décorateur Javascript

Explication détaillée des caractéristiques et exemples d'utilisation du modèle de décorateur Javascript

伊谢尔伦
伊谢尔伦original
2017-07-24 13:42:291278parcourir

Modèle de décorateur : étendez dynamiquement les fonctions de l'objet sans modifier la classe et l'héritage d'origine, et implémentez un nouvel objet avec la même interface que l'objet d'origine en encapsulant un objet.

Caractéristiques du motif décorateur :

1. Ajoutez des fonctionnalités sans modifier la structure originale de l'objet d'origine.

2. L'objet décoré et l'objet original ont la même interface, ce qui permet aux clients d'utiliser l'objet décoré de la même manière que l'objet original.

3. L'objet de décoration contient une référence à l'objet original, c'est-à-dire que l'objet de décoration est un objet emballé du véritable objet original.

Explication détaillée du modèle de décorateur Javascript :

Dans le modèle de décorateur, des fonctionnalités supplémentaires peuvent être ajoutées dynamiquement à l'objet au moment de l'exécution. Cela peut être un défi lorsqu'il s'agit de classes statiques. En Javascript, puisque les objets sont mutables, le processus d’ajout de fonctionnalités à un objet n’est pas un problème en soi.

L'une des fonctionnalités pratiques du modèle Decorator est la nature personnalisable et configurable de son comportement prévu. Vous pouvez commencer avec un objet normal avec seulement quelques fonctionnalités de base, puis choisir parmi le pool de ressources de décoration disponibles les fonctionnalités dont vous avez besoin pour améliorer l'objet normal et les décorer dans l'ordre, en particulier lorsque l'ordre de décoration est important.

Une façon d'implémenter le modèle de décorateur est de faire de chaque décorateur un objet, et cet objet contient des méthodes qui doivent être surchargées. Chaque décorateur hérite en effet de l'objet qui a été mis en valeur par le décorateur précédent. Chaque méthode de décorateur appelle la même méthode sur « l'objet hérité » et obtient sa valeur, et continue d'effectuer certaines opérations.

Commençons par l'exemple 1 :


//需要装饰的类(函数)
function Macbook() {
 this.cost = function () {
  return 1000;
 };
} 
//计算商品的包装费
function PackagingFee(macbook) {
 this.cost = function () {
  return macbook.cost() + 75;
 };
}
//计算商品的运费
function Freight(macbook) {
 this.cost = function () {
  return macbook.cost() + 300;
 };
} 
//计算商品的保险费用
function Insurance(macbook) {
 this.cost = function () {
  return macbook.cost() + 250;
 };
}
// 用法
var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook())));
console.log(myMacbook.cost());//1625

Analysons brièvement le code ci-dessus dans le code ci-dessus, un total de quatre fonctions sont définies (. Une fonction qui doit être modifiée, trois fonctions qui sont utilisées pour la modification).

Ensuite, déclarez une variable myMacbook pour pointer vers le nouvel objet Insurance. Les paramètres formels de l'objet Insurance pointent vers le nouvel objet Freight. Les paramètres formels de l'objet Freight pointent vers le nouvel objet PackagingFee. Les paramètres de l'objet PackagingFee pointent vers new hors de l'objet Macbook.

Ensuite, appelez la méthode de coût de myMacbook. De l'analyse ci-dessus, nous pouvons conclure que la valeur de myMacbook.cost() est égale à (la méthode de coût de l'objet Freight + 250), la méthode de coût de l'objet Freight est égale à (la méthode de coût de l'objet PackagingFee + 300), et la méthode de coût de l'objet PackagingFee est égale à (méthode de coût de l'objet Macbook +75).

Le résultat final est donc : la valeur de myMacbook.cost() = 250 + (300 + (75 + 1000)) = 1625.


// 用法
var myMacbook = new Insurance(new Freight(new PackagingFee(new Macbook())));
console.log(myMacbook.cost());//1625 
//上面的代码等价于下面拆分后的代码,或许拆分后代码你更能看出前后的逻辑性
var macbook = new Macbook();
var package = new PackagingFee(macbook);
var freight = new Freight(package);
var myMacbook = new Insurance(freight);
//当然,如果你不想声明这么多变量(macbook、package、freight),只用一个变量也是可以的
var macbook = new Macbook();
macbook = new PackagingFee(macbook);
macbook = new Freight(macbook);
var myMacbook = new Insurance(macbook);

Regardez à nouveau l'instance 2 :


function ConcreteClass() {
 this.performTask = function () {
  this.preTask();
  console.log('doing something');
  this.postTask();
 };
}
function AbstractDecorator(decorated) {
 this.performTask = function () {
  decorated.performTask();
 };
}
function ConcreteDecoratorClass(decorated) {
 this.base = AbstractDecorator;
 this.base(decorated);// add performTask method
 decorated.preTask = function () {
  console.log('pre-calling..');
 };
 decorated.postTask = function () {
  console.log('post-calling..');
 };
}
var concrete = new ConcreteClass();
var decorator1 = new ConcreteDecoratorClass(concrete);
decorator1.performTask();
//pre-calling..
//doing something
//post-calling..

L'instance 2 est en fait la même que l'instance 1 Très similaire, analysons-le brièvement. Tout d'abord, trois fonctions sont définies dans l'exemple 2, puis deux variables concrètes et décorateur1 sont déclarées, et enfin la méthode performTask de décorateur1 est appelée.

En un coup d'œil, il semble qu'il n'y ait pas de méthode performTask dans ConcreteDecoratorClass. Analysons d'abord les deux lignes de code suivantes :


var concrete = new ConcreteClass(); //声明一个变量concrete指向new出来的ConcreteClass对象
var decorator1 = new ConcreteDecoratorClass(concrete); //声明一个变量decorator1指向new出来的ConcreteDecoratorClass对象,并传入变量concrete作为形参

Ensuite, analysons le code de la fonction ConcreteDecoratorClass ligne par ligne :


this.base = AbstractDecorator; //定义一个当前对象(decorator1)的base属性,并指向函数AbstractDecorator
this.base(decorated); //调用base属性指向的函数,也就是调用AbstractDecorator函数,同时传入形参decorated,形参decorated指向new出来的ConcreteClass对象

En parlant de ça, il semble qu'il n'y ait toujours pas de méthode performTask dans la fonction ConcreteDecoratorClass. Le point clé est de regarder "this" !

Ceci dans la fonction ConcreteDecoratorClass pointe vers le nouvel objet ConcreteDecoratorClass (c'est-à-dire qu'il pointe vers le même objet que decorator1)

La clé pour cela dans la fonction AbstractDecorator est de voir quel objet ; appelle cette fonction, this Which object pointe vers (à partir du code "this.base = AbstractDecorator; this.base(decorated);", nous pouvons voir que l'objet ConcreteDecoratorClass nouveau de appelle la fonction AbstractDecorator), ainsi, dans la fonction AbstractDecorator, cela pointe vers le nouvel objet ConcreteDecoratorClass (pointe également vers le même objet que decorator1).

Pour résumer, nous constaterons que dans le code ci-dessus, Que ce soit this dans la fonction ConcreteDecoratorClass ou this dans la fonction AbstractDecorator, ils pointent tous vers le nouvel objet ConcreteDecoratorClass.

Ainsi, lorsque nous exécutons decorator1.performTask(), il continuera à exécuter le code dans la fonction anonyme (decorated.performTask();), et le paramètre formel décoré dans les points de fonction anonymes vers l'objet ConcreteClass et exécutez la méthode performTask de l'objet.

Jetez enfin un œil à l'exemple 3 :


var tree = {};
tree.decorate = function () {
 console.log('Make sure the tree won\'t fall');
}; 
tree.getDecorator = function (deco) {
 tree[deco].prototype = this;
 return new tree[deco];
}; 
tree.RedApples = function () {
 this.decorate = function () {
  this.RedApples.prototype.decorate(); // 第7步:先执行原型(这时候是Angel了)的decorate方法
  console.log('Add some red apples'); // 第8步 再输出 red
  // 将这2步作为RedApples的decorate方法
 }
};
tree.BlueApples = function () {
 this.decorate = function () {
  this.BlueApples.prototype.decorate(); // 第1步:先执行原型的decorate方法,也就是tree.decorate()
  console.log('Put on some blue apples'); // 第2步 再输出blue
  // 将这2步作为BlueApples的decorate方法
 }
}; 
tree.Angel = function () {
 this.decorate = function () {
  this.Angel.prototype.decorate(); // 第4步:先执行原型(这时候是BlueApples了)的decorate方法
  console.log('An angel on the top'); // 第5步 再输出angel
  // 将这2步作为Angel的decorate方法
 }
};
tree = tree.getDecorator('BlueApples'); // 第3步:将BlueApples对象赋给tree,这时候父原型里的getDecorator依然可用
tree = tree.getDecorator('Angel'); // 第6步:将Angel对象赋给tree,这时候父原型的父原型里的getDecorator依然可用
tree = tree.getDecorator('RedApples'); // 第9步:将RedApples对象赋给tree
tree.decorate(); // 第10步:执行RedApples对象的decorate方法
//Make sure the tree won't fall
//Add blue apples
//An angel on the top
//Put on some red apples

L'exemple 3 a l'air très compliqué. En fait, la logique d'analyse est toujours la même que celle de l'exemple 3. deux exemples précédents. Nous pouvons voir qu'un total de 5 expressions de fonction sont déclarées dans l'exemple 3. Concentrons-nous sur l'analyse du code suivant :


//tree.getDecorator('BlueApples')返回new出来的tree.BlueApples的实例对象,并将该对象赋值给空的tree对象
tree = tree.getDecorator('BlueApples'); //new出来的tree.BlueApples的实例对象的原型指向 --> 空对象tree 
//tree.getDecorator('Angel')返回new出来的tree.Angel的实例对象(这行代码中的第二个tree已经是上面一行代码运行结果后的tree.BlueApples的实例对象)
tree = tree.getDecorator('Angel'); //new出来的tree.Angel的实例对象的原型指向 --> tree.BlueApples的实例对象
//tree.getDecorator('RedApples')返回new出来的tree.RedApples的实例对象(这行代码中的第二个tree已经是上面一行代码运行结果后的tree.Angel的实例对象)
tree = tree.getDecorator('RedApples'); //new出来的tree.RedApples的实例对象的原型指向 --> tree.Angel的实例对象
//调用tree.decorate(),这里的tree已经是new出来的tree.RedApples的实例对象了。
//tree.RedApples的实例对象的decorate属性方法里面的第一行代码是 “this.RedApples.prototype.decorate()”
//结合上面的分析可以得出以下的原型链结构:
//this.RedApples.prototype --> tree.Angel;
//tree.Angel.prototype --> tree.BlueApples;
//tree.BlueApples.prototype --> 空对象tree
tree.decorate();

Après avoir analysé cela, il n'est pas difficile de connaître le résultat final.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn