TS结构型设计模式之装饰模式

定义

Decorators make it possible to annotate and modify classes and properties at design time.
装饰器可以让你在设计时对类和类的属性进行注解和修改

通俗来说,就是在不改变原有对象的基础上,通过对其进行包装扩展(添加属性或者方法)使原有对象可以满足用户更复杂的需求。就增加功能来说,装饰模式相对生成子类更为灵活。

实现

装饰模式有不同的实现方法,
第一种,使用继承方式,构建装饰类,传入被装饰类,进行修饰;

//被装饰的类
class Component{
     
    public operate(){
     
        console.log("做些事...");
    }
}

//装饰类
class Decorator extends Component{
     
    private component:Component
    constructor(){
     
        super();
        this.component = new Component();
    }
    
    //传入扩展功能函数
    DecorOperate(method:Function){
     
        this.operate = ()=>{
     
            method.call(this.component);
            this.component.w();
        }
    }
}

这种实现方式其实看起来和代理模式有些像,但代理目的是在目标对象方法基础上的增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。而装饰模式不会对目标对象的方法做操作,只做增加,做扩展。

第二种,使用注解方式,直接修改类及其成员,比如说使用装饰器,TS、ES都有。

装饰器种类

1、类装饰器

参数:
类的构造函数作为其唯一的参数。
返回值:
返回的构造函数来替换类的声明。

function addAge(constructor: Function) {
      } 
@addAge 
class A{
      } 

相当于

A = addAge(A) || A;

2、方法装饰器

参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 成员的属性描述符。

返回值:
用作方法的属性描述符。

如果同一个方法有多个装饰器,会像剥洋葱一样,先从外到内进入,然后由内向外执行。

// 声明装饰器修饰方法
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) 
{
     ...};

class A{
      
    name: string; 
    constructor() {
      this.name = 'xiaomuzhu'; } 
    @method 
    say(){
      }
}

相当于

let descriptor = {
      
    value: function() {
      }, 
    enumerable: false, 
    configurable: true, 
    writable: true 
}; 
descriptor = method(A.prototype, "say", descriptor) || descriptor; Object.defineProperty(A.prototype, "say", descriptor);

3、访问符装饰器

同方法装饰器。

4、属性装饰器

参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。

返回值:
忽略,没办法监视或修改一个属性的初始化方法,属性描述符只能用来监视类中是否声明了某个名字的属性。

// 声明装饰器修饰方法
function method(target: any, propertyKey: string, descriptor: PropertyDescriptor) 
{
     ...};

class A{
      
    @method 
    name: string; 
    constructor() {
      this.name = 'xiaomuzhu'; } 
}

相当于

method(A.prototype, "name") 

5、参数装饰器(TS)

应用于类的构造函数或方法声明。
参数:

  1. 对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。
  2. 成员的名字。
  3. 参数在函数参数列表中的索引。

返回值:
忽略,只能用来监视一个方法的参数是否被传入。

执行

  • 执行期间:装饰器是在声明期就执行的,这个时候类没有实例化。实例化几次类并不会致使装饰器多次执行,不会有带来额外的开销(第一种实现方式就不是如此)。
  • 执行顺序:按编码时的声明顺序执行。

应用场景

  • 需要扩展一个类的功能,或给一个类增加附加功能。(第二种方法)
  • 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。(第一种方法)
  • 需要为一批的兄弟类进行改装或加装

有这么一个说法,如果超过两层继承,就要考虑代码是不是设计有问题。装饰模式就是对继承的有力补充,解决类膨胀的问题。但多层的装饰也是很复杂,不便维护的。装饰模式,优点就是扩展性十分好,对类和对象都是一种良性扩展,不需要了解其内部具体实现,只在外部进行一次封装扩展,这是对原有功能完整性的一种保护。

参考链接:TypeScript装饰器
参考书籍:《设计模式之禅》

你可能感兴趣的:(设计模式,设计模式,javascript,typescript)