装饰器模式核心概念

  1. 装饰器模式:
    1. (Decorator Pattern) 是一种结构型设计模式,核心思想是:在不修改原有对象代码的前提下,动态地给对象添加额外的功能;
    2. 它通过 “包装” 原有对象的方式扩展功能,比继承更灵活 (避免类爆炸),符合 “开闭原则” (对扩展开放,对修改关闭)
  2. 类图:
  3. 实现代码:
    // -------------------------- 1. Component(抽象组件:MilkTea)--------------------------
    // TS 抽象类,完全匹配类图中的 MilkTea 抽象组件
    abstract class MilkTea {
      // 抽象方法(类图中标注 * 的 operation 方法),强制子类实现
      public abstract operation(): number;
    }
    
    // -------------------------- 2. ConcreteComponent(具体组件:BasicMilkTea)-------------
    // 基础奶茶类,继承抽象类 MilkTea,实现核心方法
    class BasicMilkTea extends MilkTea {
      // 实现抽象方法:返回基础奶茶价格(类型注解:返回值为 number)
      public operation(): number {
        return 10;
      }
    }
    
    // -------------------------- 3. Decorator(抽象装饰器:MilkTeaDecorator)---------------
    abstract class MilkTeaDecorator extends MilkTea {
      // 类图中标注的 milkTea 属性,TS 显式声明类型为 MilkTea
      protected milkTea: MilkTea;
    
      // 构造函数接收 MilkTea 实例,约束参数类型
      constructor(milkTea: MilkTea) {
        super();
        this.milkTea = milkTea;
      }
    
      // 抽象方法,强制子类实现(匹配类图中的 * 标记)
      public abstract operation(): number;
    }
    
    // -------------------------- 4. ConcreteDecoratorA(具体装饰器:PearlDecorator)----------
    // 珍珠装饰器,继承抽象装饰器
    class PearlDecorator extends MilkTeaDecorator {
      // 实现抽象方法:基础价格 + 珍珠加价
      public operation(): number {
        return this.milkTea.operation() + 2;
      }
    }
    
    // -------------------------- 5. ConcreteDecoratorB(具体装饰器:CheeseFoamDecorator)------
    // 奶盖装饰器,继承抽象装饰器
    class CheeseFoamDecorator extends MilkTeaDecorator {
      // 实现抽象方法:基础价格 + 奶盖加价
      public operation(): number {
        return this.milkTea.operation() + 3;
      }
    }
    
    // -------------------------- 测试代码(带类型校验)--------------------------
    // 1. 基础奶茶
    const basicTea: MilkTea = new BasicMilkTea();
    console.log("基础奶茶价格:", basicTea.operation()); // 输出:10
    
    // 2. 基础奶茶 + 珍珠(装饰器包装)
    const teaWithPearl: MilkTea = new PearlDecorator(basicTea);
    console.log("基础奶茶+珍珠价格:", teaWithPearl.operation()); // 输出:12
    
    // 3. 基础奶茶 + 珍珠 + 奶盖(多层装饰)
    const teaWithPearlAndFoam: MilkTea = new CheeseFoamDecorator(teaWithPearl);
    console.log("基础奶茶+珍珠+奶盖价格:", teaWithPearlAndFoam.operation()); // 输出:15
    
    // 4. 基础奶茶 + 奶盖
    const teaWithFoam: MilkTea = new CheeseFoamDecorator(basicTea);
    console.log("基础奶茶+奶盖价格:", teaWithFoam.operation()); // 输出:13
    

常用使用场景

ES7 装饰器语法

  1. 日志 / 性能监控:给函数添加日志打印、耗时统计,不修改函数逻辑;
  2. 实现代码:
    // 日志装饰器示例
    function logDecorator(target, name, descriptor) {
      const originalFn = descriptor.value;
      descriptor.value = function(...args) {
        console.log(`调用函数 ${name},参数:`, args);
        const result = originalFn.apply(this, args);
        console.log(`函数 ${name} 返回值:`, result);
        return result;
      };
      return descriptor;
    }
    
    class Calculator {
      @logDecorator
      add(a, b) {
        return a + b;
      }
    }
    
    const calc = new Calculator();
    calc.add(1, 2); // 自动打印日志,不修改 add 逻辑
    

Axios 拦截器

  1. Axios 的请求 / 响应拦截器本质是装饰器模式,拦截器函数,动态给请求添加 token、请求头、错误处理,不修改核心请求逻辑;
  2. 实现代码:
    // 请求拦截器(装饰请求)
    axios.interceptors.request.use(
      config => {
        // 扩展功能:添加 token
        config.headers.Authorization = "Bearer " + localStorage.getItem("token");
        return config; // 原请求对象被装饰后返回
      },
      error => Promise.reject(error)
    );
    
    // 响应拦截器(装饰响应)
    axios.interceptors.response.use(
      response => {
        // 扩展功能:统一处理响应数据
        return response.data;
      },
      error => {
        // 扩展功能:统一处理错误
        console.log("请求失败:", error);
        return Promise.reject(error);
      }
    );
    

UI 组件动态扩展

  1. React 高阶组件 (HOC) 是装饰器模式的典型应用,HOC 函数 (如 withLoading、withAuth),动态给组件添加加载状态、权限控制
  2. 实现代码:
    // 加载状态装饰器(HOC)
    function withLoading(Component) {
      return function(props) {
        if (props.isLoading) {
          return <div>加载中...</div>;
        }
        return <Component {...props} />; // 原组件被装饰后返回
      };
    }
    
    // 基础按钮组件
    const Button = ({ text }) => <button>{text}</button>;
    
    // 装饰后:带加载状态的按钮
    const ButtonWithLoading = withLoading(Button);
    
    // 使用:<ButtonWithLoading text="提交" isLoading={true} />
    

权限控制装饰器

  1. 实现代码:
    // 角色类型
    type UserRole = 'admin' | 'user' | 'guest';
    
    // 按钮接口
    interface Button {
        render(role?: UserRole): string;
    }
    
    // 基础按钮
    class BaseButton implements Button {
        render(): string {
            return '<button>点击</button>';
        }
    }
    
    // 权限装饰器
    class AuthDecorator implements Button {
        constructor(
            private button: Button,
            private requiredRole: UserRole
        ) {}
    
        render(currentUserRole?: UserRole): string {
            if (currentUserRole === this.requiredRole) {
                return this.button.render();
            }
            return '<button disabled>无权限</button>';
        }
    }
    
    // 使用示例
    const button = new BaseButton();
    const adminButton = new AuthDecorator(button, 'admin');
    
    console.log(adminButton.render('user')); // 输出禁用按钮
    console.log(adminButton.render('admin')); // 输出正常按钮
    

装饰器模式优缺点

优点

  1. 动态扩展对象功能,符合开闭原则;
  2. 比继承更灵活,避免类爆炸;
  3. 可以组合多个装饰器;
  4. 装饰器和被装饰对象可以独立变化;

缺点

  1. 增加系统复杂度;
  2. 多层装饰会增加调试难度;
  3. 可能产生大量小对象;

适用场景

  1. 需要动态、透明地给对象添加职责;
  2. 需要扩展功能但不想修改原有类;
  3. 需要大量独立功能的组合;
  4. 不想使用继承导致子类过多的情况;
打赏作者
您的打赏是我前进的动力
微信
支付宝
评论

你好👏🏻,我是 ✍🏻   疯狂 codding 中...

粽子

这有关于前端开发的技术文档和你分享。

相信你可以在这里找到对你有用的知识和教程。

了解更多

目录

  1. 1. 装饰器模式核心概念
  2. 2. 常用使用场景
    1. 2.1. ES7 装饰器语法
    2. 2.2. Axios 拦截器
    3. 2.3. UI 组件动态扩展
    4. 2.4. 权限控制装饰器
  3. 3. 装饰器模式优缺点
    1. 3.1. 优点
    2. 3.2. 缺点
  4. 4. 适用场景