前端常用的 JavaScript 设计模式,吃透掌握即可所向披靡、无所畏惧

647 阅读7分钟

在前端开发中,设计模式可以帮助我们更好地组织代码、提高可维护性和可扩展性。以下是前端开发中常用的一些设计模式及其具体应用示例。

1. 单例模式(Singleton Pattern)

单例模式确保一个类只有一个实例,并提供一个全局访问点。

示例代码
class Singleton {
  static instance = null;

  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    this.data = {};
    Singleton.instance = this;
  }

  getData(key) {
    return this.data[key];
  }

  setData(key, value) {
    this.data[key] = value;
  }
}

const singleton1 = new Singleton();
singleton1.setData('name', 'bob');

const singleton2 = new Singleton();
console.log(singleton2.getData('name')); // 输出 "bob"

2. 工厂模式(Factory Pattern)

工厂模式提供了一种创建对象的接口,但允许子类决定实例化哪个类。

示例代码
function createShape(type) {
  switch (type) {
    case 'circle':
      return new Circle();
    case 'square':
      return new Square();
    default:
      throw new Error('Invalid shape type');
  }
}

class Shape {
  draw() {
    console.log('Drawing a shape...');
  }
}

class Circle extends Shape {
  draw() {
    console.log('Drawing a circle...');
  }
}

class Square extends Shape {
  draw() {
    console.log('Drawing a square...');
  }
}

const circle = createShape('circle');
circle.draw(); // 输出 "Drawing a circle..."

const square = createShape('square');
square.draw(); // 输出 "Drawing a square..."

3. 观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。

示例代码
class Subject {
  constructor() {
    this.observers = [];
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    this.observers = this.observers.filter(obs => obs !== observer);
  }

  notify(data) {
    this.observers.forEach(observer => observer.update(data));
  }
}

class Observer {
  update(data) {
    console.log(`Received data: ${data}`);
  }
}

const subject = new Subject();
const observer1 = new Observer();
const observer2 = new Observer();

subject.addObserver(observer1);
subject.addObserver(observer2);

subject.notify('Hello, world!'); // 输出 "Received data: Hello, world!"

4. 发布订阅模式(Publish/Subscribe Pattern)

发布订阅模式是一种消息通信模式,对象之间通过事件进行通信。

示例代码
class EventBus {
  constructor() {
    this.subscribers = {};
  }

  subscribe(event, callback) {
    if (!this.subscribers[event]) {
      this.subscribers[event] = [];
    }
    this.subscribers[event].push(callback);
  }

  publish(event, data) {
    const callbacks = this.subscribers[event];
    if (callbacks) {
      callbacks.forEach(callback => callback(data));
    }
  }
}

const eventBus = new EventBus();

eventBus.subscribe('message', data => console.log(`Received message: ${data}`));

eventBus.publish('message', 'Hello, world!'); // 输出 "Received message: Hello, world!"

5. 模块模式(Module Pattern)

模块模式用于封装私有变量和方法,同时暴露公共接口。

示例代码
const MyModule = (function () {
  const privateData = 'Private data';

  function privateMethod() {
    console.log('Private method called');
  }

  return {
    publicMethod: function () {
      console.log('Public method called');
      privateMethod();
      console.log(privateData);
    }
  };
})();

MyModule.publicMethod(); // 输出 "Public method called", "Private method called", "Private data"

6. 代理模式(Proxy Pattern)

代理模式为另一个对象提供一个代理或占位符,以便控制对这个对象的访问。

示例代码
class RealSubject {
  request() {
    console.log('RealSubject: Handling request.');
  }
}

class Proxy {
  constructor(realSubject) {
    this.realSubject = realSubject;
  }

  request() {
    if (this.checkAccess()) {
      this.realSubject.request();
    }
  }

  checkAccess() {
    console.log('Proxy: Checking access before calling RealSubject.');
    return true;
  }
}

const realSubject = new RealSubject();
const proxy = new Proxy(realSubject);

proxy.request(); // 输出 "Proxy: Checking access befor

7. 装饰器模式(Decorator Pattern) 装饰器本质是函数

装饰器模式允许在不改变对象结构的情况下动态地添加职责。

示例代码
function log(target, key, descriptor) {
  const originalMethod = descriptor.value;

  descriptor.value = function (...args) {
    console.log(`Calling ${key} with`, args);
    const result = originalMethod.apply(this, args);
    console.log(`Called ${key} returned`, result);
    return result;
  };

  return descriptor;
}

class MyClass {
  @log
  myMethod(message) {
    console.log(message);
  }
}

const instance = new MyClass();
instance.myMethod('Hello, world!'); // 输出 "Calling myMethod with [ 'Hello, world!' ]", "Hello, world!", "Called myMethod returned undefined"

8. 策略模式(Strategy Pattern)

策略模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换。

示例代码
class StrategyA {
  execute(data) {
    console.log(`Executing strategy A with data: ${data}`);
  }
}

class StrategyB {
  execute(data) {
    console.log(`Executing strategy B with data: ${data}`);
  }
}

class Context {
  constructor(strategy) {
    this.strategy = strategy;
  }

  setStrategy(strategy) {
    this.strategy = strategy;
  }

  executeStrategy(data) {
    this.strategy.execute(data);
  }
}

const context = new Context(new StrategyA());
context.executeStrategy('some data'); // 输出 "Executing strategy A with data: some data"

context.setStrategy(new StrategyB());
context.executeStrategy('other data'); // 输出 "Executing strategy B with data: other data"

9. 组合模式(Composite Pattern)

组合模式使得你能够将对象组合成树形结构以表示部分-整体层次结构。

示例代码
class Component {
  constructor(name) {
    this.name = name;
  }

  add(component) {
    throw new Error('Not implemented');
  }

  remove(component) {
    throw new Error('Not implemented');
  }

  display(level) {
    throw new Error('Not implemented');
  }
}

class Leaf extends Component {
  display(level) {
    console.log(`${' '.repeat(level * 2)}Leaf: ${this.name}`);
  }
}

class Composite extends Component {
  constructor(name) {
    super(name);
    this.children = [];
  }

  add(component) {
    this.children.push(component);
  }

  remove(component) {
    this.children = this.children.filter(child => child !== component);
  }

  display(level) {
    console.log(`${' '.repeat(level * 2)}Composite: ${this.name}`);
    this.children.forEach(child => child.display(level + 1));
  }
}

const root = new Composite('root');
const leaf1 = new Leaf('leaf1');
const leaf2 = new Leaf('leaf2');
const composite1 = new Composite('composite1');
const leaf3 = new Leaf('leaf3');

root.add(leaf1);
root.add(composite1);
composite1.add(leaf2);
composite1.add(leaf3);

root.display(0); // 输出 "Composite: root", "  Leaf: leaf1", "  Composite: composite1", "    Leaf: leaf2", "    Leaf: leaf3"

10. 责任链模式(Chain of Responsibility Pattern)

责任链模式使得多个对象有机会处理请求,直到其中一个对象处理为止。

示例代码
class Handler {
  constructor(successor) {
    this.successor = successor;
  }

  handleRequest(request) {
    if (this.successor) {
      this.successor.handleRequest(request);
    }
  }
}

class ConcreteHandler1 extends Handler {
  handleRequest(request) {
    if (request === 1) {
      console.log('ConcreteHandler1 handled request');
    } else {
      super.handleRequest(request);
    }
  }
}

class ConcreteHandler2 extends Handler {
  handleRequest(request) {
    if (request === 2) {
      console.log('ConcreteHandler2 handled request');
    } else {
      super.handleRequest(request);
    }
  }
}

class ConcreteHandler3 extends Handler {
  handleRequest(request) {
    if (request === 3) {
      console.log('ConcreteHandler3 handled request');
    } else {
      super.handleRequest(request);
    }
  }
}

const handler1 = new ConcreteHandler1(new ConcreteHandler2(new ConcreteHandler3(null)));
handler1.handleRequest(1); // 输出 "ConcreteHandler1 handled request"
handler1.handleRequest(2); // 输出 "ConcreteHandler2 handled request"
handler1.handleRequest(3); // 输出 "ConcreteHandler3 handled request"

举例说明实际开发类库中用到比较多的

1. 观察者模式(Observer Pattern)

观察者模式在前端框架中非常常见,特别是在响应式数据绑定和事件驱动的场景中。

应用场景
  • Vue.js:Vue.js 使用观察者模式来实现数据的双向绑定。
  • React:虽然 React 不直接使用观察者模式,但它通过 useEffect 钩子实现了类似的功能。
示例代码(Vue.js)
// Vue.js 实现中的简单观察者模式
class Observer {
  constructor(value) {
    this.value = value;
    this.walk(value);
  }

  walk(obj) {
    Object.keys(obj).forEach(key => {
      this.defineReactive(obj, key, obj[key]);
    });
  }

  defineReactive(obj, key, val) {
    this.observe(val);
    Object.defineProperty(obj, key, {
      get() {
        console.log(`Getting ${key}: ${val}`);
        return val;
      },
      set(newVal) {
        if (newVal !== val) {
          console.log(`Setting ${key}: ${newVal}`);
          val = newVal;
        }
      }
    });
  }

  observe(val) {
    if (val && typeof val === 'object') {
      new Observer(val);
    }
  }
}

const data = { message: 'Hello Vue!' };
const observer = new Observer(data);

data.message = 'Updated message'; // 输出 "Setting message: Updated message"
console.log(data.message); // 输出 "Updated message"
2. 发布订阅模式(Publish/Subscribe Pattern)

发布订阅模式在前端框架中用于事件管理和异步通信。

应用场景
  • Vue.js:Vue.js 中的事件总线(Event Bus)。
  • Angular:RxJS 库中的 Observable。
  • React:Redux 中的中间件(如 redux-saga)。
示例代码(Vue.js 事件总线)
// Vue.js 事件总线实现
class EventBus {
  constructor() {
    this.subscribers = {};
  }

  $on(event, callback) {
    if (!this.subscribers[event]) {
      this.subscribers[event] = [];
    }
    this.subscribers[event].push(callback);
  }

  $emit(event, ...args) {
    const callbacks = this.subscribers[event];
    if (callbacks) {
      callbacks.forEach(callback => callback(...args));
    }
  }
}

const eventBus = new EventBus();

eventBus.$on('message', data => console.log(`Received message: ${data}`));

eventBus.$emit('message', 'Hello, world!'); // 输出 "Received message: Hello, world!"
3. 单例模式(Singleton Pattern)

单例模式用于确保全局唯一实例,常用于状态管理和其他全局服务。

应用场景
  • Redux:全局状态管理。
  • Vuex:Vue.js 的状态管理库。
示例代码(Redux)
// Redux 中的单例模式
import { createStore } from 'redux';

const initialState = {
  count: 0
};

function reducer(state = initialState, action) {
  switch (action.type) {
    case 'INCREMENT':
      return { ...state, count: state.count + 1 };
    case 'DECREMENT':
      return { ...state, count: state.count - 1 };
    default:
      return state;
  }
}

const store = createStore(reducer);

store.subscribe(() => {
  console.log(store.getState());
});

store.dispatch({ type: 'INCREMENT' }); // 输出 "{ count: 1 }"
store.dispatch({ type: 'INCREMENT' }); // 输出 "{ count: 2 }"
4. 工厂模式(Factory Pattern)

工厂模式用于创建对象的接口,常用于组件工厂和其他创建逻辑。

应用场景
  • React:组件工厂。
  • Vue.js:组件工厂。
示例代码(React 组件工厂)
// React 组件工厂
function createComponent(type) {
  switch (type) {
    case 'button':
      return <button>Button</button>;
    case 'input':
      return <input type="text" />;
    default:
      throw new Error('Invalid component type');
  }
}

const button = createComponent('button');
const input = createComponent('input');

console.log(button); // 输出 "<button>Button</button>"
console.log(input); // 输出 "<input type="text" />"

5. 装饰器模式(Decorator Pattern)

装饰器模式用于动态地添加功能,常用于增强类的功能。

应用场景
  • React:高阶组件(Higher-Order Components)。
  • Vue.js:装饰器(如 @watch)。
示例代码(React 高阶组件)
// React 高阶组件
function withLogging(WrappedComponent) {
  return class extends React.Component {
    componentDidMount() {
      console.log('Component mounted');
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
}

class Button extends React.Component {
  render() {
    return <button>{this.props.children}</button>;
  }
}

const LoggingButton = withLogging(Button);

ReactDOM.render(<LoggingButton>Click me</LoggingButton>, document.getElementById('root'));
6. 策略模式(Strategy Pattern)

策略模式用于封装一系列算法,常用于不同的策略实现。

应用场景
  • Vue.js:路由守卫(Route Guards)。
  • React:路由配置(Route Configurations)。
示例代码(Vue.js 路由守卫)
// Vue.js 路由守卫
const authGuard = to => {
  if (isAuthenticated()) {
    return true;
  }
  return '/login';
};

const guestGuard = to => {
  if (!isAuthenticated()) {
    return true;
  }
  return '/';
};

const router = new VueRouter({
  routes: [
    { path: '/', component: HomeComponent, beforeEnter: guestGuard },
    { path: '/dashboard', component: DashboardComponent, beforeEnter: authGuard }
  ]
});
7. 适配器模式(Adapter Pattern)

适配器模式用于适配不同的接口,常用于第三方库的集成。

应用场景
  • Vue.js:适配不同数据源。
  • React:适配不同 API。
示例代码(Vue.js 适配器)
// Vue.js 适配器
class ThirdPartyAPI {
  fetchData() {
    return Promise.resolve({ data: 'Third party data' });
  }
}

class AdapterAPI {
  constructor(api) {
    this.api = api;
  }

  fetchCustomData() {
    return this.api.fetchData().then(response => ({
      customData: response.data
    }));
  }
}

const thirdPartyAPI = new ThirdPartyAPI();
const adapterAPI = new AdapterAPI(thirdPartyAPI);

adapterAPI.fetchCustomData().then(data => console.log(data)); // 输出 "{ customData: 'Third party data' }"

总结

  • 单例模式:确保一个类只有一个实例。
  • 工厂模式:创建对象的接口。
  • 观察者模式:对象之间的一对多依赖关系。
  • 发布订阅模式:基于事件的消息通信。
  • 模块模式:封装私有变量和方法。
  • 代理模式:为另一个对象提供代理。
  • 装饰器模式:动态地添加职责。
  • 命令模式:封装请求。
  • 策略模式:封装一系列算法。
  • 适配器模式:使不兼容的接口匹配。
  • 组合模式:表示部分-整体层次结构。
  • 责任链模式:多个对象处理请求。
  • 状态模式:对象在内部状态改变时改变行为。

以上是前端开发中常用的一些设计模式及其具体应用示例。通过这些设计模式,我们可以更好地组织代码,提高代码的可维护性和可扩展性。每种模式都有其特定的应用场景,选择合适的设计模式可以显著提升代码质量和开发效率。