探索 JS 中五大常用设计模式,再也别说设计模式没用啦!

开发 前端
今天,咱们来看一下 JS 中的常用设计模式。主要有 5 种,一起来了解一下吧。

今天,咱们来看一下 JS 中的常用设计模式。主要有 5 种:

  1. 单例模式
  2. 观察者模式
  3. 工厂模式
  4. 模块模式
  5. 装饰器模式

一、单例模式

单例模式是一种设计模式,它确保一个类只有一个实例,并提供一个全局访问点来获取这个实例。

在 JavaScript 中,单例模式通常用于 创建唯一的对象实例,例如全局配置、共享资源或状态管理器。这样可以避免重复创建实例,节省资源,并确保全局数据的一致性。

在前端框架中的应用

  1. Vue.js: 在 Vue 中,单例模式通常用来创建 Vuex store(状态管理器),它确保整个应用程序只有一个 store 实例
// store.js
import Vue from 'vue';
import Vuex from 'vuex';

Vue.use(Vuex);

const store = new Vuex.Store({
 state: {
   count: 0
 },
 mutations: {
   increment(state) {
     state.count++;
   }
 }
});

export default store;
  1. React: 在 React 中,类似的单例模式可以用于创建全局状态管理库,如 Redux 或者 React Context API。Redux 的 store 也是一个单例,确保整个应用使用的是同一个状态树。
// store.js
import { createStore } from 'redux';

const initialState = { count: 0 };

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

const store = createStore(reducer);

export default store;

单例模式的基本实现

通过闭包来实现单例模式:

const Singleton = (function () {
  let instance;

  function createInstance() {
    return { name: "张三" };
  }

  return {
    getInstance: function () {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();

// 使用示例
const instance1 = Singleton.getInstance();
const instance2 = Singleton.getInstance();

console.log(instance1 === instance2); // true

适用场景

  1. 全局配置: 当你需要一个全局唯一的配置对象,供整个应用程序使用时,比如应用的配置设置、日志系统等。
  2. 状态管理: 当你需要一个全局的状态管理工具(如 Vuex 或 Redux)来管理应用程序的状态,确保状态的一致性和集中管理。

二、观察者模式

观察者模式用于定义对象之间的一对多依赖关系。

当一个对象的状态发生变化时,所有依赖于它的对象都会得到通知并自动更新。这个模式通常用于实现发布-订阅(pub-sub)机制。

主要优点在于它提供了一个解耦的方式来管理对象之间的依赖关系。

在前端框架中的应用

  1. Vue.js: Vue2 的响应式系统就是基于观察者模式的。当 Vue 组件的依赖数据发生变化时,相关组件会被重新渲染。
// Vue 组件示例
new Vue({
 el: '#app',
 data: {
   message: 'Hello Vue!'
 }
});
  1. React: React 使用了类似于观察者模式的机制来实现组件的重新渲染。当组件的状态(state)或属性(props)发生变化时,React 会重新渲染相关的组件。
class MyComponent extends React.Component {
 constructor(props) {
   super(props);
   this.state = { message: 'Hello React!' };
 }

 render() {
   return <div>{this.state.message}</div>;
 }
}

观察者模式的基本实现

通过事件监听机制来实现:

class Subject {
  constructor() {
    this.observers = [];
  }

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

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

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

class Observer {
  update(data) {
    console.log(`数据为: ${data}`);
  }
}

适用场景

  1. 事件处理: 当需要处理用户交互、系统事件或其他异步事件时。例如,监听按钮点击事件或处理服务器推送的数据。
  2. 数据绑定: 在构建数据驱动的用户界面时(类似 vue),例如:表单数据和视图之间的双向绑定,观察者模式可以帮助自动更新视图。
  3. 发布-订阅系统: 当需要构建一个松耦合的系统,其中多个组件可以订阅和发布事件时,观察者模式是一个很好的选择。例如,实现聊天系统中的消息通知功能。

三、工厂模式

工厂模式是一种创建型设计模式,用于定义一个创建对象的接口,但让子类决定实例化哪个类。

工厂模式通过将对象的创建过程封装到一个工厂类中,使得代码可以在不暴露对象创建逻辑的情况下使用这些对象。主要优点在于对象的创建和使用之间的耦合度降低。

在前端框架中的应用

  1. Vue.js: Vue 的组件系统可以被视为工厂模式的一种实现。在 Vue 中,你可以使用工厂函数来创建不同的组件实例。例如,Vue 的 Vue.component 方法实际上就是一个工厂方法,它用来注册和创建组件。
// 注册一个全局组件
Vue.component('my-component', {
 template: '<div>Hello World</div>'
});

// 创建组件实例
new Vue({
 el: '#app',
 template: '<my-component></my-component>'
});
  1. React: React 的组件创建和管理也是工厂模式的一种应用。你可以定义组件类或函数组件,然后 React 会根据需要创建和管理这些组件的实例。
function MyComponent() {
 return <div>Hello World</div>;
}

// 使用组件
ReactDOM.render(<MyComponent />, document.getElementById('root'));

工厂模式的基本实现

工厂模式可以通过函数或类来实现:

// 工厂函数
function Car(make, model) {
  this.make = make;
  this.model = model;
}

function createCar(make, model) {
  return new Car(make, model);
}

// 使用示例
const car1 = createCar('理想', 'L9');
const car2 = createCar('问界', 'M9');

console.log(car1); // Car { make: '理想', model: 'L9' }
console.log(car2); // Car { make: '问界', model: 'M9' }

适用场景

  1. 对象创建逻辑复杂: 当对象的创建过程复杂,涉及到多个步骤或配置时,工厂模式可以将这些细节封装起来。
  2. 对象实例化的变体: 当需要创建不同类型的对象,但对象的创建过程基本相似时,可以使用工厂模式来简化创建过程。例如,根据不同的配置创建不同类型的组件或模块。
  3. 依赖注入: 当需要在创建对象时注入不同的依赖项或配置时,工厂模式可以帮助管理这些依赖项并确保对象的正确初始化。
  4. 解耦: 当需要将对象的创建和使用解耦时,工厂模式可以提供一个统一的创建接口,使得客户端代码不需要关心对象的具体创建过程。

四、模块模式

模块模式用于创建一个具有私有和公有方法的模块,并封装模块的内部状态。这种模式在前端的框架或者项目中是使用最广的。

在前端框架中的应用

  1. Vue.js: Vue.js 中的单文件组件(.vue 文件)实际上就是模块化的方案,它允许将模板、脚本和样式封装在一个文件中,并通过 export 和 import 语法来管理这些模块
<!-- MyComponent.vue -->
<template>
 <div>{{message}}</div>
</template>

<script>
export default {
 data() {
   return {
     message: 'Hello Vue!'
   };
 }
};
</script>

<style>
div {
 color: red;
}
</style>
  1. React: 在 React 中,组件也是一种模块化的实践。每个组件通常都放在一个单独的文件中,这样可以封装组件的状态和逻辑。React 使用 ES6 的 import 和 export 来管理组件模块。
// MyComponent.js
import React from 'react';

function MyComponent() {
 return <div>Hello, React!</div>;
}

export default MyComponent;
// App.js
import React from 'react';
// 模块化
import MyComponent from './MyComponent';

function App() {
 return (
   <div>
     <MyComponent />
   </div>
 );
}

export default App;

模块模式的基本实现

在 JavaScript 中,模块模式通常通过立即调用的函数表达式(IIFE)来实现。这种模式能够封装模块的私有变量和方法,同时暴露一些公有接口给外部使用。

const myModule = (function() {
  // 私有变量和方法
  let privateVar = '我是私有的';

  function privateMethod() {
    console.log(privateVar);
  }

  // 公有变量和方法
  return {
    publicVar: '我是公有的',
    publicMethod: function() {
      privateMethod();
    }
  };
})();

适用场景

  1. 封装和组织代码: 当你需要封装内部逻辑,避免全局命名冲突,并将功能模块化时,可以使用模块模式。
  2. 私有和公有方法: 当需要隐藏模块的私有方法和变量,仅暴露必要的公有接口时,模块模式提供了一种清晰的方式来实现这一点。
  3. 代码复用: 当你希望将功能或组件拆分成独立的模块,以便在不同的地方复用时,模块模式可以帮助你更好地组织和管理这些模块。

五、装饰器模式

装饰器模式是一种结构型设计模式,用于动态地为对象添加额外的功能,而不修改其结构。它通常会通过创建一个装饰器对象来包装原始对象,并在装饰器对象中添加或修改功能。

在前端框架中的应用

在 Vue 或者 react 中,虽然没有直接使用装饰器模式,但有类似的概念,如 Vue 的 mixins 和 React 的高阶组件。

  1. Vue.js: Vue 的 mixins 功能可以看作是一种装饰器模式的实现。Mixins 允许你将可复用的功能代码抽象成一个对象,并将其混入到 Vue 组件中,以便共享和复用。
// 定义一个 mixin
const myMixin = {
 data() {
   return {
     mixinData: '我是 mixin 的数据'
   };
 },
 methods: {
   mixinMethod() {
     console.log('我是 mixin 的方法');
   }
 }
};

// 使用 mixin
new Vue({
 el: '#app',
 mixins: [myMixin],
 created() {
   this.mixinMethod(); // '我是 mixin 的数据'
 }
});
  1. React: 在 React 中,装饰器模式也不是直接使用的,但高阶组件(HOC)可以看作是一种装饰器模式的应用。HOC 是一个函数,接受一个组件并返回一个新的组件,该新组件增加了额外的功能或数据。
// 高阶组件
function withExtraProps(WrappedComponent) {
 return function EnhancedComponent(props) {
   return <WrappedComponent {...props} extraProp="extra" />;
 };
}

// 原始组件
function MyComponent(props) {
 return <div>{props.extraProp}</div>;
}

// 使用高阶组件
const EnhancedComponent = withExtraProps(MyComponent);

ReactDOM.render(<EnhancedComponent />, document.getElementById('root'));

装饰器模式的基本实现

装饰器模式可以通过高阶函数或类装饰器来实现:

// 原始对象
class Coffee {
  cost() {
    return 5;
  }
}

// 装饰器函数
function MilkDecorator(coffee) {
  const originalCost = coffee.cost();
  coffee.cost = function() {
    return originalCost + 2;
  };
  return coffee;
}

// 使用示例
const myCoffee = new Coffee();
console.log(myCoffee.cost()); // 5

const myMilkCoffee = MilkDecorator(myCoffee);
console.log(myMilkCoffee.cost()); // 7

适用场景

  1. 动态扩展功能: 当你需要在运行时动态地为对象添加功能,而不修改对象的结构时,装饰器模式提供了一种灵活的方式来实现这一点。
  2. 组合功能: 当你需要组合多个装饰器来创建一个具有多个功能的对象时,装饰器模式提供了一种清晰的方式来实现这一点。
责任编辑:华轩 来源: 程序员Sunday
相关推荐

2011-09-07 09:21:01

设计模式

2024-10-21 16:34:15

2012-10-29 11:16:13

2023-12-26 08:20:40

2024-04-25 09:24:19

系统设计开发

2010-06-12 16:42:03

UML设计

2009-10-14 11:19:11

桌面虚拟化模式

2020-05-25 10:20:19

享元模式场景

2014-12-29 10:39:16

JS

2023-09-22 11:58:49

2020-06-22 07:00:00

软件架构架构模式

2023-11-29 18:06:15

Python设计模式

2021-02-01 10:01:58

设计模式 Java单例模式

2019-04-02 09:23:40

设计模式前端JavaScript

2012-08-30 09:07:33

设计模式

2023-11-28 11:22:51

Pythonitertools库工具

2023-11-02 21:11:11

JavaScript设计模式

2010-07-14 17:03:52

编程语言

2021-04-18 21:07:32

门面模式设计

2024-01-09 09:06:13

点赞
收藏

51CTO技术栈公众号