设计模式

4 阅读3分钟

一、设计模式的本质与分类

定义:设计模式是软件开发中反复出现的问题的通用解决方案,由GoF(四人组)在1994年归纳为23种经典模式。

三大分类

  1. 创建型模式:解决对象创建问题(如单例、工厂);
  2. 结构型模式:解决对象组合问题(如装饰器、适配器);
  3. 行为型模式:解决对象交互问题(如观察者、策略)。

二、创建型模式(解决对象创建)

1. 单例模式(Singleton)
  • 核心思想:确保类只有一个实例,全局可访问。
  • 实现要点
    class Singleton {
      constructor() {
        if (!Singleton.instance) {
          Singleton.instance = this;
        }
        return Singleton.instance;
      }
    }
    
    // 使用
    const s1 = new Singleton();
    const s2 = new Singleton();
    console.log(s1 === s2); // true
    
  • 应用场景:全局状态管理(如Vuex的store)、弹窗管理器。
2. 工厂模式(Factory)
  • 核心思想:将对象创建逻辑封装,客户端无需知道具体实现。
  • 简单工厂示例
    // 产品接口
    class Product {
      constructor(name) {
        this.name = name;
      }
      use() {
        console.log(`使用${this.name}`);
      }
    }
    
    // 工厂
    class Factory {
      createProduct(name) {
        return new Product(name);
      }
    }
    
    // 使用
    const factory = new Factory();
    const product = factory.createProduct('手机');
    product.use(); // 使用手机
    
  • 应用场景:Vue组件动态注册、前端路由配置。

三、结构型模式(解决对象组合)

1. 装饰器模式(Decorator)
  • 核心思想:动态为对象添加新功能,不修改原类。
  • 示例(为函数添加日志功能)
    // 原始函数
    function doTask() {
      console.log('执行任务');
    }
    
    // 装饰器
    function withLog(func) {
      return function() {
        console.log('开始时间:', new Date());
        const result = func.apply(this, arguments);
        console.log('结束时间:', new Date());
        return result;
      };
    }
    
    // 使用
    const taskWithLog = withLog(doTask);
    taskWithLog(); 
    // 输出:开始时间... 执行任务 结束时间...
    
  • 应用场景:React高阶组件(HOC)、Redux的middleware。
2. 适配器模式(Adapter)
  • 核心思想:将不兼容的接口转换为兼容的接口。
  • 示例(适配旧API)
    // 旧接口
    const oldAPI = {
      fetchData: function(callback) {
        // 回调风格API
        setTimeout(() => callback('旧数据'), 100);
      }
    };
    
    // 适配器
    const adapter = {
      fetchData() {
        return new Promise((resolve) => {
          oldAPI.fetchData(resolve);
        });
      }
    };
    
    // 使用Promise风格
    adapter.fetchData().then(data => console.log(data));
    
  • 应用场景:兼容不同浏览器API(如EventEmitter适配器)。

四、行为型模式(解决对象交互)

1. 观察者模式(Observer)
  • 核心思想:对象间建立一对多依赖,当一个对象变化时,所有依赖者都会收到通知。
  • 示例(事件总线)
    class EventEmitter {
      constructor() {
        this.events = {};
      }
      on(event, callback) {
        if (!this.events[event]) this.events[event] = [];
        this.events[event].push(callback);
      }
      emit(event, data) {
        if (this.events[event]) {
          this.events[event].forEach(callback => callback(data));
        }
      }
    }
    
    // 使用
    const emitter = new EventEmitter();
    emitter.on('message', (data) => console.log('收到消息:', data));
    emitter.emit('message', 'Hello'); // 收到消息: Hello
    
  • 应用场景:Vue的响应式系统、DOM事件机制。
2. 策略模式(Strategy)
  • 核心思想:定义一系列算法,将每个算法封装,使它们可互换。
  • 示例(表单验证)
    const strategies = {
      isRequired(value) {
        return value ? true : '不能为空';
      },
      isEmail(value) {
        return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) ? true : '请输入正确邮箱';
      }
    };
    
    class Validator {
      constructor() {
        this.rules = [];
      }
      add(field, strategy, errorMsg) {
        this.rules.push(() => {
          const value = this[field];
          const result = strategies[strategy](value);
          return result === true ? '' : `${field} ${result}`;
        });
      }
      validate() {
        for (const rule of this.rules) {
          const error = rule();
          if (error) return error;
        }
        return '';
      }
    }
    
    // 使用
    const form = new Validator();
    form.add('username', 'isRequired', '必填');
    form.add('email', 'isEmail', '格式错误');
    form.username = '';
    form.email = 'invalid';
    console.log(form.validate()); // username 必填
    
  • 应用场景:排序算法切换、动画效果策略。

五、问题

1. 问:前端中常用的设计模式有哪些?请举例说明。

  • 单例模式:Vuex的store、全局状态管理;
  • 观察者模式:Vue的响应式系统、事件总线(EventBus);
  • 装饰器模式:React高阶组件(HOC)、Redux middleware;
  • 工厂模式:Vue组件动态创建、Element UI的组件工厂;
  • 适配器模式:不同浏览器API兼容(如Fetch API适配器)。
2. 问:装饰器模式和继承的区别是什么?

  • 装饰器模式
    • 动态添加功能,不修改原类;
    • 一个对象可被多个装饰器装饰(如React组件被多个HOC包裹);
    • 符合开闭原则(对扩展开放,对修改关闭)。
  • 继承
    • 静态继承父类功能,需修改类结构;
    • 单继承限制(JS中类只能继承一个父类);
    • 可能导致类层次复杂(“继承地狱”)。
3. 问:为什么React Hooks替代了部分设计模式?

  • 状态逻辑复用:Hooks(如useEffectuseReducer)替代了装饰器模式(HOC)的部分场景,避免组件嵌套过深;
  • 简化组件结构:Hooks使逻辑抽离更灵活(如useFetch自定义Hook替代适配器模式);
  • 性能优化:Hooks减少了组件重渲染范围,比高阶组件更高效。

六、设计原则与模式的关系

四大设计原则(SOLID)

  • 单一职责(Single Responsibility):一个类只负责一项职责;
  • 开闭原则(Open-Closed):软件实体对扩展开放,对修改关闭;
  • 里氏替换(Liskov Substitution):子类可替换父类且不破坏程序;
  • 接口隔离(Interface Segregation):多个特定接口优于单一大接口;
  • 依赖倒置(Dependency Inversion):高层模块不依赖低层模块,依赖抽象。

关系:设计模式是实现设计原则的具体方案,如:

  • 单例模式体现单一职责;
  • 装饰器模式遵循开闭原则;
  • 工厂模式实现依赖倒置。