Skip to content

装饰器模式详解:概念、实现与应用

引言

装饰器模式是一种结构型设计模式,它允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。装饰器模式能够在不修改原对象代码的情况下,动态地给对象添加新的功能。

什么是装饰器模式?

装饰器模式是一种结构型设计模式,它能将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。装饰器模式通过创建一个装饰器类来包装原有的类,可以在保持原有类结构不变的情况下增加新的功能。

核心思想

装饰器模式的核心思想是:

  1. 动态扩展:在运行时动态地给对象添加功能
  2. 透明性:装饰器对象对外提供与被装饰对象相同的接口
  3. 组合优于继承:通过组合而非继承来扩展功能

为什么需要装饰器模式?

在许多情况下,我们需要在不修改原有代码的情况下扩展对象的功能:

1. 功能增强

当需要给对象添加额外功能时:

  • 添加日志记录功能
  • 添加权限检查功能
  • 添加缓存功能

2. 避免子类爆炸

当使用继承扩展功能会导致类数量急剧增加时:

  • 每个功能组合都需要一个子类
  • 类层次结构变得复杂
  • 难以维护和扩展

3. 运行时动态配置

当需要在运行时动态决定添加哪些功能时:

  • 根据配置添加不同功能
  • 根据用户权限添加不同功能
  • 根据环境添加不同功能

装饰器模式的基本实现

让我们从一个简单的装饰器模式实现开始:

javascript
// 组件接口(定义对象的基本功能)
class Component {
  operation() {
    throw new Error('必须实现 operation 方法');
  }
}

// 具体组件(实现基本功能)
class ConcreteComponent extends Component {
  operation() {
    return '具体组件的操作';
  }
}

// 装饰器基类(实现与 Component 相同的接口)
class Decorator extends Component {
  constructor(component) {
    super();
    this.component = component;
  }
  
  operation() {
    return this.component.operation();
  }
}

// 具体装饰器 A
class ConcreteDecoratorA extends Decorator {
  operation() {
    return `装饰器A(${super.operation()})`;
  }
}

// 具体装饰器 B
class ConcreteDecoratorB extends Decorator {
  operation() {
    return `装饰器B[${super.operation()}]`;
  }
}

// 客户端代码
function clientCode(component) {
  console.log(`结果: ${component.operation()}`);
}

// 使用原始组件
const simple = new ConcreteComponent();
console.log('客户端:我可以使用简单组件:');
clientCode(simple);

// 使用装饰后的组件
const decorator1 = new ConcreteDecoratorA(simple);
const decorator2 = new ConcreteDecoratorB(decorator1);
console.log('客户端:我可以使用装饰后的组件:');
clientCode(decorator2);

实现要点分析

  1. 组件接口:定义对象的基本功能
  2. 具体组件:实现基本功能的具体类
  3. 装饰器基类:持有组件引用,实现与组件相同的接口
  4. 具体装饰器:扩展功能的具体装饰器类
  5. 客户端:通过组件接口与对象交互

装饰器模式的实际应用场景

1. HTTP 请求装饰器

在 Web 开发中,装饰器模式非常适合用于增强 HTTP 请求功能:

javascript
// HTTP 请求接口
class HTTPRequest {
  send() {
    throw new Error('必须实现 send 方法');
  }
}

// 基本 HTTP 请求
class BasicHTTPRequest extends HTTPRequest {
  constructor(url, method = 'GET', data = null) {
    super();
    this.url = url;
    this.method = method;
    this.data = data;
  }
  
  send() {
    return `发送 ${this.method} 请求到 ${this.url}${this.data ? `,数据: ${JSON.stringify(this.data)}` : ''}`;
  }
}

// HTTP 请求装饰器基类
class HTTPRequestDecorator extends HTTPRequest {
  constructor(request) {
    super();
    this.request = request;
  }
  
  send() {
    return this.request.send();
  }
}

// 日志装饰器
class LoggingDecorator extends HTTPRequestDecorator {
  send() {
    const startTime = Date.now();
    console.log(`[日志] 开始发送请求: ${this.request.url}`);
    
    const result = super.send();
    
    const endTime = Date.now();
    console.log(`[日志] 请求完成,耗时: ${endTime - startTime}ms`);
    
    return result;
  }
}

// 认证装饰器
class AuthenticationDecorator extends HTTPRequestDecorator {
  constructor(request, token) {
    super(request);
    this.token = token;
  }
  
  send() {
    console.log(`[认证] 添加认证头: Bearer ${this.token}`);
    // 这里可以实际添加认证头到请求中
    return super.send();
  }
}

// 重试装饰器
class RetryDecorator extends HTTPRequestDecorator {
  constructor(request, maxRetries = 3) {
    super(request);
    this.maxRetries = maxRetries;
  }
  
  send() {
    let lastError;
    
    for (let i = 0; i <= this.maxRetries; i++) {
      try {
        if (i > 0) {
          console.log(`[重试] 第 ${i} 次重试`);
        }
        return super.send();
      } catch (error) {
        lastError = error;
        if (i < this.maxRetries) {
          // 等待一段时间后重试
          console.log(`[重试] 等待 1000ms 后重试...`);
        }
      }
    }
    
    throw new Error(`请求失败,已重试 ${this.maxRetries} 次: ${lastError.message}`);
  }
}

// 缓存装饰器
class CacheDecorator extends HTTPRequestDecorator {
  constructor(request, cache = new Map()) {
    super(request);
    this.cache = cache;
  }
  
  send() {
    const cacheKey = `${this.request.method}:${this.request.url}`;
    
    if (this.cache.has(cacheKey)) {
      console.log(`[缓存] 从缓存中获取数据: ${cacheKey}`);
      return this.cache.get(cacheKey);
    }
    
    console.log(`[缓存] 发送请求并缓存结果: ${cacheKey}`);
    const result = super.send();
    this.cache.set(cacheKey, result);
    return result;
  }
}

// 请求管理器
class RequestManager {
  constructor() {
    this.cache = new Map();
  }
  
  createRequest(url, method = 'GET', data = null) {
    return new BasicHTTPRequest(url, method, data);
  }
  
  createLoggedRequest(url, method = 'GET', data = null) {
    const request = this.createRequest(url, method, data);
    return new LoggingDecorator(request);
  }
  
  createAuthenticatedRequest(url, method = 'GET', data = null, token) {
    const request = this.createRequest(url, method, data);
    const authDecorator = new AuthenticationDecorator(request, token);
    return new LoggingDecorator(authDecorator);
  }
  
  createCachedRequest(url, method = 'GET', data = null) {
    const request = this.createRequest(url, method, data);
    return new CacheDecorator(request, this.cache);
  }
  
  createRobustRequest(url, method = 'GET', data = null, token = null) {
    let request = this.createRequest(url, method, data);
    
    // 添加认证(如果有令牌)
    if (token) {
      request = new AuthenticationDecorator(request, token);
    }
    
    // 添加日志
    request = new LoggingDecorator(request);
    
    // 添加重试
    request = new RetryDecorator(request, 3);
    
    // 添加缓存
    request = new CacheDecorator(request, this.cache);
    
    return request;
  }
}

// 使用示例
function httpRequestExample() {
  const requestManager = new RequestManager();
  
  console.log('=== 基本请求 ===');
  const basicRequest = requestManager.createRequest('https://api.example.com/users', 'GET');
  console.log(basicRequest.send());
  
  console.log('\n=== 带日志的请求 ===');
  const loggedRequest = requestManager.createLoggedRequest('https://api.example.com/users', 'POST', { name: '张三' });
  console.log(loggedRequest.send());
  
  console.log('\n=== 带认证的请求 ===');
  const authRequest = requestManager.createAuthenticatedRequest('https://api.example.com/users', 'GET', null, 'token123');
  console.log(authRequest.send());
  
  console.log('\n=== 带缓存的请求 ===');
  const cachedRequest1 = requestManager.createCachedRequest('https://api.example.com/users');
  console.log(cachedRequest1.send());
  
  const cachedRequest2 = requestManager.createCachedRequest('https://api.example.com/users');
  console.log(cachedRequest2.send());
  
  console.log('\n=== 健壮的请求(多重装饰) ===');
  const robustRequest = requestManager.createRobustRequest('https://api.example.com/users', 'GET', null, 'token456');
  console.log(robustRequest.send());
}

httpRequestExample();

2. 数据处理管道装饰器

在数据处理中,装饰器模式非常适合用于构建处理管道:

javascript
// 数据处理器接口
class DataProcessor {
  process(data) {
    throw new Error('必须实现 process 方法');
  }
}

// 基本数据处理器
class BasicDataProcessor extends DataProcessor {
  process(data) {
    return data;
  }
}

// 数据处理器装饰器基类
class DataProcessorDecorator extends DataProcessor {
  constructor(processor) {
    super();
    this.processor = processor;
  }
  
  process(data) {
    return this.processor.process(data);
  }
}

// 数据验证装饰器
class ValidationDecorator extends DataProcessorDecorator {
  process(data) {
    console.log('[验证] 验证数据格式');
    
    // 简单的验证逻辑
    if (!data || typeof data !== 'object') {
      throw new Error('数据格式无效');
    }
    
    return super.process(data);
  }
}

// 数据转换装饰器
class TransformDecorator extends DataProcessorDecorator {
  constructor(processor, transformFunction) {
    super(processor);
    this.transformFunction = transformFunction;
  }
  
  process(data) {
    console.log('[转换] 转换数据');
    const transformedData = this.transformFunction(data);
    return super.process(transformedData);
  }
}

// 数据加密装饰器
class EncryptionDecorator extends DataProcessorDecorator {
  process(data) {
    console.log('[加密] 加密数据');
    // 简单的"加密"示例
    const encryptedData = typeof data === 'string' ? 
      Buffer.from(data).toString('base64') : 
      Buffer.from(JSON.stringify(data)).toString('base64');
    
    return super.process(encryptedData);
  }
}

// 数据压缩装饰器
class CompressionDecorator extends DataProcessorDecorator {
  process(data) {
    console.log('[压缩] 压缩数据');
    // 简单的"压缩"示例
    const compressedData = typeof data === 'string' ? 
      data.replace(/\s+/g, '') : 
      JSON.stringify(data).replace(/\s+/g, '');
    
    return super.process(compressedData);
  }
}

// 日志装饰器
class LoggingDecorator extends DataProcessorDecorator {
  process(data) {
    console.log(`[日志] 处理数据: ${JSON.stringify(data)}`);
    const result = super.process(data);
    console.log(`[日志] 处理结果: ${JSON.stringify(result)}`);
    return result;
  }
}

// 错误处理装饰器
class ErrorHandlingDecorator extends DataProcessorDecorator {
  process(data) {
    try {
      return super.process(data);
    } catch (error) {
      console.error(`[错误处理] 捕获错误: ${error.message}`);
      // 可以选择重新抛出错误或返回默认值
      throw error;
    }
  }
}

// 数据处理管道
class DataProcessingPipeline extends DataProcessor {
  constructor() {
    super();
    this.decorators = [];
  }
  
  addDecorator(decorator) {
    this.decorators.push(decorator);
    return this;
  }
  
  process(data) {
    // 创建基本处理器
    let processor = new BasicDataProcessor();
    
    // 按顺序应用装饰器
    for (const decorator of this.decorators) {
      // 创建装饰器实例并包装当前处理器
      processor = new decorator.constructor.name === 'Function' ? 
        new decorator(processor) : 
        Object.assign(Object.create(decorator), { processor });
    }
    
    return processor.process(data);
  }
}

// 数据处理工厂
class DataProcessorFactory {
  static createValidator() {
    return ValidationDecorator;
  }
  
  static createTransformer(transformFunction) {
    return class extends DataProcessorDecorator {
      process(data) {
        console.log('[转换] 转换数据');
        const transformedData = transformFunction(data);
        return super.process(transformedData);
      }
    };
  }
  
  static createEncryptor() {
    return EncryptionDecorator;
  }
  
  static createCompressor() {
    return CompressionDecorator;
  }
  
  static createLogger() {
    return LoggingDecorator;
  }
  
  static createErrorHandler() {
    return ErrorHandlingDecorator;
  }
}

// 使用示例
function dataProcessingExample() {
  // 创建处理管道
  const pipeline = new DataProcessingPipeline();
  
  // 添加装饰器(按顺序)
  pipeline.addDecorator(new ValidationDecorator())
         .addDecorator(DataProcessorFactory.createTransformer(data => {
           // 转换数据:添加时间戳
           return {
             ...data,
             processedAt: new Date().toISOString()
           };
         }))
         .addDecorator(new LoggingDecorator())
         .addDecorator(new CompressionDecorator())
         .addDecorator(new EncryptionDecorator());
  
  console.log('=== 处理用户数据 ===');
  try {
    const userData = { name: '张三', age: 30, email: 'zhangsan@example.com' };
    const result = pipeline.process(userData);
    console.log('处理结果:', result);
  } catch (error) {
    console.error('处理失败:', error.message);
  }
  
  console.log('\n=== 处理无效数据 ===');
  try {
    const invalidData = null;
    const result = pipeline.process(invalidData);
    console.log('处理结果:', result);
  } catch (error) {
    console.error('处理失败:', error.message);
  }
}

dataProcessingExample();

3. UI 组件装饰器

在前端开发中,装饰器模式非常适合用于增强 UI 组件功能:

javascript
// UI 组件接口
class UIComponent {
  render() {
    throw new Error('必须实现 render 方法');
  }
  
  onClick(callback) {
    this.clickHandler = callback;
  }
  
  triggerClick() {
    if (this.clickHandler) {
      this.clickHandler();
    }
  }
}

// 基本文本按钮
class TextButton extends UIComponent {
  constructor(text) {
    super();
    this.text = text;
  }
  
  render() {
    return `<button>${this.text}</button>`;
  }
}

// UI 组件装饰器基类
class UIComponentDecorator extends UIComponent {
  constructor(component) {
    super();
    this.component = component;
    this.clickHandler = null;
  }
  
  render() {
    return this.component.render();
  }
  
  onClick(callback) {
    this.clickHandler = callback;
  }
  
  triggerClick() {
    if (this.clickHandler) {
      this.clickHandler();
    }
    this.component.triggerClick();
  }
}

// 样式装饰器
class StyleDecorator extends UIComponentDecorator {
  constructor(component, styles = {}) {
    super(component);
    this.styles = styles;
  }
  
  render() {
    const originalRender = super.render();
    const styleString = Object.entries(this.styles)
      .map(([key, value]) => `${key.replace(/([A-Z])/g, '-$1').toLowerCase()}: ${value}`)
      .join('; ');
    
    // 在按钮标签中添加样式
    return originalRender.replace('<button', `<button style="${styleString}"`);
  }
}

// 工具提示装饰器
class TooltipDecorator extends UIComponentDecorator {
  constructor(component, tooltipText) {
    super(component);
    this.tooltipText = tooltipText;
  }
  
  render() {
    const originalRender = super.render();
    return originalRender.replace('<button', `<button title="${this.tooltipText}"`);
  }
}

// 禁用状态装饰器
class DisabledDecorator extends UIComponentDecorator {
  constructor(component) {
    super(component);
    this.disabled = false;
  }
  
  setDisabled(disabled) {
    this.disabled = disabled;
  }
  
  render() {
    const originalRender = super.render();
    if (this.disabled) {
      return originalRender.replace('<button', `<button disabled`);
    }
    return originalRender;
  }
  
  triggerClick() {
    if (!this.disabled) {
      super.triggerClick();
    } else {
      console.log('[禁用] 按钮已禁用,无法点击');
    }
  }
}

// 加载状态装饰器
class LoadingDecorator extends UIComponentDecorator {
  constructor(component, loadingText = '加载中...') {
    super(component);
    this.loading = false;
    this.loadingText = loadingText;
  }
  
  setLoading(loading) {
    this.loading = loading;
  }
  
  render() {
    if (this.loading) {
      return `<button disabled>${this.loadingText}</button>`;
    }
    return super.render();
  }
  
  triggerClick() {
    if (!this.loading) {
      super.triggerClick();
    } else {
      console.log('[加载] 按钮正在加载,无法点击');
    }
  }
}

// 防抖装饰器
class DebounceDecorator extends UIComponentDecorator {
  constructor(component, delay = 300) {
    super(component);
    this.delay = delay;
    this.timeoutId = null;
  }
  
  triggerClick() {
    if (this.timeoutId) {
      clearTimeout(this.timeoutId);
    }
    
    this.timeoutId = setTimeout(() => {
      super.triggerClick();
      this.timeoutId = null;
    }, this.delay);
  }
}

// 统计装饰器
class AnalyticsDecorator extends UIComponentDecorator {
  constructor(component, eventName) {
    super(component);
    this.eventName = eventName;
    this.clickCount = 0;
  }
  
  triggerClick() {
    this.clickCount++;
    console.log(`[统计] ${this.eventName} 被点击 ${this.clickCount} 次`);
    super.triggerClick();
  }
}

// UI 组件工厂
class UIComponentFactory {
  static createButton(text) {
    return new TextButton(text);
  }
  
  static createStyledButton(text, styles) {
    const button = new TextButton(text);
    return new StyleDecorator(button, styles);
  }
  
  static createTooltipButton(text, tooltip) {
    const button = new TextButton(text);
    return new TooltipDecorator(button, tooltip);
  }
  
  static createAdvancedButton(text, options = {}) {
    let button = new TextButton(text);
    
    // 应用样式
    if (options.styles) {
      button = new StyleDecorator(button, options.styles);
    }
    
    // 添加工具提示
    if (options.tooltip) {
      button = new TooltipDecorator(button, options.tooltip);
    }
    
    // 添加禁用功能
    if (options.disableable) {
      button = new DisabledDecorator(button);
    }
    
    // 添加加载状态
    if (options.loadable) {
      button = new LoadingDecorator(button);
    }
    
    // 添加防抖
    if (options.debounce) {
      button = new DebounceDecorator(button, options.debounce);
    }
    
    // 添加统计
    if (options.analytics) {
      button = new AnalyticsDecorator(button, options.analytics);
    }
    
    return button;
  }
}

// 使用示例
function uiComponentExample() {
  console.log('=== 基本按钮 ===');
  const basicButton = UIComponentFactory.createButton('点击我');
  console.log('渲染:', basicButton.render());
  basicButton.onClick(() => console.log('基本按钮被点击'));
  basicButton.triggerClick();
  
  console.log('\n=== 带样式的按钮 ===');
  const styledButton = UIComponentFactory.createStyledButton('样式按钮', {
    backgroundColor: 'blue',
    color: 'white',
    padding: '10px 20px',
    borderRadius: '5px'
  });
  console.log('渲染:', styledButton.render());
  styledButton.onClick(() => console.log('样式按钮被点击'));
  styledButton.triggerClick();
  
  console.log('\n=== 带工具提示的按钮 ===');
  const tooltipButton = UIComponentFactory.createTooltipButton('提示按钮', '这是一个有用的提示');
  console.log('渲染:', tooltipButton.render());
  tooltipButton.onClick(() => console.log('提示按钮被点击'));
  tooltipButton.triggerClick();
  
  console.log('\n=== 高级按钮 ===');
  const advancedButton = UIComponentFactory.createAdvancedButton('高级按钮', {
    styles: {
      backgroundColor: 'green',
      color: 'white',
      padding: '10px 20px',
      border: 'none',
      borderRadius: '5px'
    },
    tooltip: '这是一个高级按钮',
    disableable: true,
    loadable: true,
    debounce: 500,
    analytics: 'advanced_button_click'
  });
  
  console.log('渲染:', advancedButton.render());
  advancedButton.onClick(() => console.log('高级按钮被点击'));
  
  // 测试禁用功能
  const disabledDecorator = advancedButton.component.component.component.component; // 获取 DisabledDecorator
  disabledDecorator.setDisabled(true);
  console.log('禁用后渲染:', advancedButton.render());
  advancedButton.triggerClick();
  
  // 启用按钮
  disabledDecorator.setDisabled(false);
  console.log('启用后渲染:', advancedButton.render());
  
  // 测试加载状态
  const loadingDecorator = advancedButton.component.component.component; // 获取 LoadingDecorator
  loadingDecorator.setLoading(true);
  console.log('加载中渲染:', advancedButton.render());
  advancedButton.triggerClick();
  
  // 完成加载
  loadingDecorator.setLoading(false);
  console.log('加载完成渲染:', advancedButton.render());
  
  // 测试正常点击
  advancedButton.triggerClick();
  
  // 测试防抖
  console.log('\n=== 测试防抖 ===');
  for (let i = 0; i < 5; i++) {
    setTimeout(() => {
      console.log(`触发点击 ${i + 1}`);
      advancedButton.triggerClick();
    }, i * 100);
  }
}

uiComponentExample();

装饰器模式的两种实现方式

透明装饰器

透明装饰器对外提供与被装饰对象相同的接口:

javascript
// 透明装饰器示例
class TransparentDecorator extends Component {
  constructor(component) {
    super();
    this.component = component;
  }
  
  operation() {
    // 增强功能但保持接口一致
    console.log('装饰器增强功能');
    return this.component.operation();
  }
}

不透明装饰器

不透明装饰器提供与被装饰对象不同的接口:

javascript
// 不透明装饰器示例
class OpaqueDecorator extends Component {
  constructor(component) {
    super();
    this.component = component;
  }
  
  operation() {
    return this.component.operation();
  }
  
  // 新增的方法
  enhancedOperation() {
    console.log('增强的操作');
    return this.operation();
  }
}

装饰器模式与其它模式的对比

装饰器模式 vs 适配器模式

javascript
// 装饰器模式 - 增强功能
class Decorator {
  operation() {
    // 增强原有功能
    return `装饰后: ${this.component.operation()}`;
  }
}

// 适配器模式 - 转换接口
class Adapter {
  request() {
    // 转换为不同的接口
    return this.adaptee.specificRequest();
  }
}

装饰器模式 vs 代理模式

javascript
// 装饰器模式 - 增强功能
class Decorator {
  operation() {
    // 添加新功能
    console.log('添加日志');
    return this.component.operation();
  }
}

// 代理模式 - 控制访问
class Proxy {
  operation() {
    // 控制对真实对象的访问
    if (this.checkAccess()) {
      return this.realSubject.operation();
    }
    return '访问被拒绝';
  }
}

装饰器模式的优缺点

优点

  1. 单一职责原则:可以将核心业务逻辑与装饰功能分开
  2. 开闭原则:无需修改原有代码即可扩展对象功能
  3. 灵活性:可以在运行时添加或删除功能
  4. 组合性:可以使用多个装饰器来组合多种行为
  5. 可复用性:装饰器可以在不同对象间复用

缺点

  1. 复杂性增加:引入大量小型类会增加系统的复杂性
  2. 调试困难:多个装饰器叠加时,调试可能变得困难
  3. 性能开销:装饰器链较长时可能带来性能开销
  4. 初始化繁琐:创建被装饰对象时可能需要处理多个装饰器

总结

装饰器模式是一种结构型设计模式,它允许通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。装饰器模式能够在不修改原对象代码的情况下,动态地给对象添加新的功能。

通过本章的学习,我们了解了:

  1. 装饰器模式的基本概念和核心思想
  2. 装饰器模式的实现方式(透明装饰器和不透明装饰器)
  3. 装饰器模式在实际开发中的应用场景(HTTP请求、数据处理、UI组件)
  4. 装饰器模式与其他结构型模式的对比
  5. 装饰器模式的优缺点

装饰器模式在现代软件开发中应用广泛,特别是在需要动态扩展对象功能而不修改原有代码的场景中,它可以很好地支持系统的灵活性和可维护性。

在下一章中,我们将继续探讨其他结构型模式,首先是代理模式。