Skip to content

前端设计模式 (Design Patterns)

设计模式是软件开发中常见问题的典型解决方案。在前端开发中,虽然很多模式被框架(如 React/Vue)隐藏了,但理解它们有助于写出更优雅的代码。

1. 单例模式 (Singleton)

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

javascript
// 场景:全局状态管理 (Vuex/Redux Store)、全局模态框
class Singleton {
  constructor() {
    if (!Singleton.instance) {
      this.data = [];
      Singleton.instance = this;
    }
    return Singleton.instance;
  }
}

const s1 = new Singleton();
const s2 = new Singleton();
console.log(s1 === s2); // true

2. 观察者模式 (Observer) / 发布-订阅模式 (Pub-Sub)

观察者模式:Subject(目标)和 Observer(观察者)直接关联。 发布-订阅模式:通过 Event Center(调度中心)作为中介,Publisher 和 Subscriber 不直接认识。

javascript
// 简单的发布-订阅 (Event Emitter)
class EventEmitter {
  constructor() {
    this.events = {};
  }
  
  on(event, callback) {
    if (!this.events[event]) this.events[event] = [];
    this.events[event].push(callback);
  }
  
  emit(event, ...args) {
    if (this.events[event]) {
      this.events[event].forEach(cb => cb(...args));
    }
  }
}

// 场景:Vue 的 EventBus、DOM 事件监听

3. 代理模式 (Proxy)

为其他对象提供一种代理以控制对这个对象的访问。

javascript
// 场景:ES6 Proxy 实现数据响应式 (Vue 3)
const data = { count: 0 };

const proxy = new Proxy(data, {
  get(target, key) {
    console.log(`Reading ${key}`);
    return target[key];
  },
  set(target, key, value) {
    console.log(`Writing ${key} = ${value}`);
    target[key] = value;
    // 触发 UI 更新...
    return true;
  }
});

4. 工厂模式 (Factory)

定义一个创建对象的接口,但让子类决定实例化哪一个类。

javascript
// 场景:jQuery 的 $('div'),React.createElement
function createElement(type, config) {
  if (type === 'image') {
    return new Image(config);
  } else if (type === 'video') {
    return new Video(config);
  }
}

5. 策略模式 (Strategy)

定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。

javascript
// 场景:表单验证
const strategies = {
  isNonEmpty: (val, errorMsg) => val === '' ? errorMsg : void 0,
  minLength: (val, length, errorMsg) => val.length < length ? errorMsg : void 0,
  isMobile: (val, errorMsg) => !/^1[3|5|8][0-9]{9}$/.test(val) ? errorMsg : void 0
};

// 使用时只需要指定使用哪个策略,而不需要写大量的 if-else

6. 装饰器模式 (Decorator)

在不改变对象自身的基础上,在程序运行期间给对象动态地添加职责。

javascript
// 场景:ES7 Decorator, React HOC (高阶组件)
// @readonly
// class Person { ... }

function withLog(Component) {
  return function(props) {
    console.log('Rendering component...');
    return <Component {...props} />;
  }
}

7. 适配器模式 (Adapter)

将一个类的接口转换成客户希望的另外一个接口。

javascript
// 场景:Vue 的 computed 属性(将数据适配为另一种格式),
// 或者由 Axios 适配浏览器 (XHR) 和 Node (http) 环境。

MIT Licensed | Keep Learning.