>웹 프론트엔드 >JS 튜토리얼 >자바스크립트 데코레이터 패턴의 특징과 사용예를 자세히 설명

자바스크립트 데코레이터 패턴의 특징과 사용예를 자세히 설명

伊谢尔伦
伊谢尔伦원래의
2017-07-24 13:42:291330검색

데코레이터 패턴: 원본 클래스 및 상속을 변경하지 않고 개체 기능을 동적으로 확장하고 개체를 래핑하여 원본 개체와 동일한 인터페이스로 새 개체를 구현합니다.

데코레이터 패턴의 특징:

1. 원본 객체의 원래 구조를 변경하지 않고 기능을 추가합니다.

2. 장식된 개체와 원본 개체의 인터페이스가 동일하므로 고객은 장식된 개체를 원본 개체와 동일하게 사용할 수 있습니다.

3. 장식 개체에는 원본 개체에 대한 참조가 포함되어 있습니다. 즉, 장식 개체는 실제 원본 개체의 패키지 개체입니다.

Javascript 데코레이터 패턴에 대한 자세한 설명:

데코레이터 패턴에서는 런타임 시 객체에 추가 기능을 동적으로 추가할 수 있습니다. 이는 정적 클래스를 다룰 때 어려울 수 있습니다. Javascript에서는 객체가 변경 가능하기 때문에 객체에 기능을 추가하는 과정 자체는 문제가 되지 않습니다.

데코레이터 패턴의 가장 편리한 기능 중 하나는 의도된 동작의 사용자 정의 및 구성이 가능하다는 것입니다. 몇 가지 기본 기능만 있는 일반 개체로 시작한 다음, 사용 가능한 장식 리소스 풀에서 일반 개체를 향상시키는 데 필요한 기능을 선택하고, 특히 장식 순서가 중요한 경우 순서대로 장식할 수 있습니다.

데코레이터 패턴을 구현하는 한 가지 방법은 각 데코레이터를 객체로 만드는 것입니다. 객체에는 오버로드되어야 하는 메서드가 포함되어 있습니다. 각 데코레이터는 실제로 이전 데코레이터에 의해 강화된 개체를 상속합니다. 각 데코레이터 메서드는 "상속된 개체"에 대해 동일한 메서드를 호출하고 해당 값을 가져오며 일부 작업을 계속 수행합니다.

예제 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

위 코드를 간략하게 분석해 보겠습니다. 위 코드에는 총 4개의 함수(수정이 필요한 함수 1개, 수정에 사용되는 함수 3개)가 정의되어 있습니다. ).

그런 다음, 새로운 Insurance 객체를 가리키는 myMacbook 변수를 선언하세요. Freight 객체의 공식 매개변수는 새로운 PackagingFee 객체를 가리킵니다. 개체는 새로운 Macbook 개체를 가리킵니다.

다음으로 myMacbook의 비용 메소드를 호출합니다. 위 분석에서 myMacbook.cost()의 값은 (Freight 객체의 비용 메소드 + 250)과 같고, Freight 객체의 비용 메소드는 (PackagingFee 객체의 비용 메소드)와 같다고 결론을 내릴 수 있습니다. + 300), PackagingFee 객체의 비용 방법은 (Macbook 객체의 비용 방법 +75)와 같습니다.

최종 결과는 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);

예제 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..

인스턴스 2는 실제로 예 1과 매우 유사하므로 간단히 분석해 보겠습니다. 먼저 예제 2에서는 3개의 함수를 정의한 후, 두 개의 변수 Concrete와 decorator1을 선언하고, 마지막으로 decorator1의 PerformTask 메소드를 호출한다.

얼핏 보면 ConcreteDecoratorClass에는 PerformTask 메소드가 없는 것처럼 보입니다. 먼저 다음 두 줄의 코드를 분석해 보겠습니다.


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

그런 다음 ConcreteDecoratorClass 함수의 코드를 한 줄씩 분석해 보겠습니다.


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

그러고 보니 아직 PerformTask가 없는 것 같습니다. ConcreteDecoratorClass 함수. 핵심은 "this"을 보는 것입니다!

ConcreteDecoratorClass 함수에서 이것은 새로운 ConcreteDecoratorClass 객체를 가리킵니다(즉, decorator1과 동일한 객체를 가리킵니다).

AbstractDecorator 함수에서 이것의 핵심은 어떤 객체가 이 함수를 호출하는지 확인하는 것입니다. 어떤 개체(" this.base = AbstractDecorator; this.base(장식된);" 코드에서 새 ConcreteDecoratorClass 개체가 AbstractDecorator 함수를 호출하는 것을 볼 수 있습니다.) AbstractDecorator 함수의 이 개체는 새 ConcreteDecoratorClass 개체를 가리킵니다(또한 decorator1이 동일한 객체를 가리킴). 요약하자면, 위의 코드에서

ConcreteDecoratorClass 함수의 이것이든 AbstractDecorator 함수의 이것이든 모두 새로운 ConcreteDecoratorClass 개체를 가리킨다는 것을 알 수 있습니다.

따라서 decorator1.performTask()를 실행하면 익명 함수(furated.performTask();)의 코드가 계속 실행됩니다. 익명 함수의 장식된 형식 매개변수는 새 ConcreteClass 객체를 가리킵니다. 개체의 PerformTask 메서드를 실행합니다.

마지막으로 예제 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

예제 3은 매우 복잡해 보입니다. 실제로 분석 논리는 이전 두 예제와 동일합니다. 예시 3. 다음 코드를 집중적으로 분석해 보겠습니다.

//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();

이를 분석한 후 최종 출력 결과를 아는 것은 어렵지 않습니다.

위 내용은 자바스크립트 데코레이터 패턴의 특징과 사용예를 자세히 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.