前端开发之装饰器模式

介绍

装饰器模式 是在不修改对象内部结构的情况下,动态地给对象添加功能的一种设计模式。在软件开发中,有时候我们需要为已有对象添加一些额外的行为,但不希望修改该对象的代码,装饰器模式可以很好的满足这一需求。

在TypeScript中,装饰器是一个函数,它可以用来注入或修改类、方法、属性或参数的行为。装饰器在编译阶段被执行,它会接收被装饰的目标作为参数,并且可以返回一个新的构造函数或方法。

装饰器的使用需要在 tsconfig.json 或者 tsconfig.app.json 中启用如下配置:

XML 复制代码
{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}
TypeScript 复制代码
class Circle {
  draw() {
    console.log("画圆");
  }
}

class Decorator {
  private circle: Circle;
  constructor(circle: Circle) {
    this.circle = circle;
  }
  draw() {
    this.circle.draw(); // 原有功能
    this.setBorder(); // 装饰
  }
  private setBorder() {
    console.log("设置边框颜色");
  }
}

const circle = new Circle();
const  decorator = new Decorator(circle)
decorator.draw()

符合开放封闭原则:

  1. 装饰器和目标分离,解耦
  2. 装饰器可自由扩展
  3. 目标可自由扩展

场景

(1)类装饰器

类装饰器用于装饰整个类,通常用来扩展或修改类的功能。

TypeScript 复制代码
function LogClass(target: Function) {
  console.log(`Class decorated: ${target.name}`);
}

@LogClass
class ExampleClass {
  constructor() {
    console.log("ExampleClass instance created");
  }
}

const ec = new ExampleClass()
// Class decorated: ExampleClass
// ExampleClass instance created

在这个例子中,LogClass 装饰器会在 ExampleClass 类定义时打印信息。

(2)方法装饰器

方法装饰器用于装饰类中的方法,它可以对方法进行一些增强操作,例如添加日志、性能监控等。

TypeScript 复制代码
function LogMethod(target: any, propertyName: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function (...args: any[]) {
        console.log(`Method ${propertyName} called with arguments: ${args}`);
        return originalMethod.apply(this, args);
    };
    return descriptor;
}

class Calculator {
    @LogMethod
    add(a: number, b: number): number {
        return a + b;
    }
}

const calc = new Calculator();
calc.add(2, 3);  // 输出: Method add called with arguments: 2,3

在这个例子中,LogMethod 会拦截 add 方法的调用并记录传递的参数。

(3)属性装饰器

属性装饰器用于装饰类中的属性,它可以用来改变属性的元数据或做一些额外的处理。

TypeScript 复制代码
function Readonly(target: any, propertyName: string) {
    Object.defineProperty(target, propertyName, {
        writable: false
    });
}

class Person {
    @Readonly
    name: string = "John";
}

const person = new Person();
person.name = "Jane";  // 这里会报错,因为 name 是只读的

在这个例子中,Readonly 装饰器将 name 属性设置为不可修改。

(4)参数装饰器

参数装饰器用于装饰方法的参数,它通常用于对参数进行校验或元数据的处理。

TypeScript 复制代码
function LogParameter(target: any, methodName: string, parameterIndex: number) {
    console.log(`Parameter in ${methodName} at index ${parameterIndex} is decorated`);
}

class User {
    greet(@LogParameter message: string) {
        console.log(message);
    }
}

const user = new User();
user.greet("Hello!");  // 输出: Parameter in greet at index 0 is decorated

在这个例子中,LogParameter 装饰器记录了 greet 方法的参数装饰情况。

AOP

面向切面编程(AOP,Aspect Oriented Program)是一种编程范式,通过将横切关注点(例如日志、事务管理等)从主要逻辑中分离出来,提高了代码的模块化和可重用性。在 TypeScript 中,AOP 可以与装饰器模式结合使用,以在代码的不同部分(方法、函数等)应用相同的横切关注点。

一个常见的 AOP 应用场景是性能监控,例如计算方法执行时间的装饰器:

TypeScript 复制代码
function measure(target: any, key: string, descriptor: PropertyDescriptor) {
    const originalMethod = descriptor.value;
    descriptor.value = function(...args: any[]) {
        const startTime = performance.now();
        const result = originalMethod.apply(this, args);
        const endTime = performance.now();
        console.log(`Method ${key} took ${(endTime - startTime).toFixed(2)} ms`);
        return result;
    };
    return descriptor;
}

class Example {
    @measure
    process(data: string) {
        // 模拟一个耗时操作
        let result = '';
        for (let i = 0; i < 1000000; i++) {
            result += data;
        }
        return result;
    }
}

const example = new Example();
const result = example.process("test"); 
// 输出方法执行时间:Method process took 32.30 ms

在这个示例中,measure 装饰器被应用于 process 方法,用来测量方法执行时间并输出日志。

相关推荐
程序员JerrySUN1 小时前
设计模式每日硬核训练 Day 14:组合模式(Composite Pattern)完整讲解与实战应用
设计模式·组合模式
碎梦归途1 小时前
23种设计模式-创建型模式之工厂方法模式(Java版本)
java·设计模式·工厂方法模式
XU磊2602 小时前
Java 工厂设计模式详解:用统一入口打造灵活可扩展的登录系统----掌握 Spring 源码的基础第一步
java·设计模式
匹马夕阳2 小时前
java开发中的设计模式之工厂模式
java·设计模式
Pasregret2 小时前
设计模式入门:从 GoF 分类到 SOLID 原则实战
java·设计模式
Light605 小时前
Python依赖注入完全指南:高效解耦、技术深析与实践落地
python·设计模式·单元测试·fastapi·依赖注入·解耦
都叫我大帅哥6 小时前
代码界的「俄罗斯套娃」:组合模式的嵌套艺术
java·后端·设计模式
渊渟岳9 小时前
为了掌握设计模式,开发了一款Markdown 文本编辑器软件(已开源)
java·设计模式
邪恶的贝利亚12 小时前
设计模式实践:模板方法、观察者与策略模式详解
设计模式·策略模式
匹马夕阳17 小时前
Java开发中的设计模式之观察者模式详细讲解
java·观察者模式·设计模式