前端设计模式的应用 | 青训营

69 阅读5分钟

前端设计模式应用

什么是设计模式?

简单来说就是软件设计中常见问题的解决方案模型

常见问题:就是历史经验的总结

解决方案模型:与特定语言无关

设计模式分类

23 种设计模式

  • 创建型 - 如何创建一个对象
  • 结构型 - 如何灵活的将对象组装成较大的结构
  • 行为型 - 负责对象间的高效通信和职责划分

浏览器中的设计模式

单例模式

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

单例模式是一种创建型设计模式,它确保一个类只有一个实例,并提供了一个全局访问点来访问该实例,经常在缓存,全局状态管理等应用场景中使用。

在前端中最常见的单例模式就是window对象,我们在任何一个地方都能够访问到它,并且在任何一个地方的修改在另外任何一个使用它的地方体现。

单例模式应用

class Person {
  instance = null;
  constructor() {
    this.name = "张三";
    this.age = 20;
  }
  static getInstance = () => {
    if (this.instance) {
      return this.instance;
    } else {
      this.instance = new Person();
      return this.instance;
    }
  };
}

const p1 = Person.getInstance();
const p2 = Person.getInstance();
console.log(p2.name);
p1.name = "李四";
console.log(p2.name);
console.log(p1, p2);

其核心思想在于,每次创建实例,返回的都是同一个实例,每次调用request返回的都是同一个cache对象

res.png

发布订阅模式

发布订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

从系统架构之间的解耦,到业务中一些实现模式,像邮件订阅,上线订阅等等,应用广泛。

实际上,只要我们曾经在 DOM 节点上面绑定过事件函数,那我们就曾经使用过发布订阅模式。例如我们在空白页面某处执行了点击操作,不管你点的地方有没有按钮,他都会触发许多事件,一次鼠标点击可以触发mousedownmouseup以及click等等等等事件。但我们都知道,点击空白处是不会发生任何响应的,这是因为我们没有给这个操作绑定相关的订阅者,或者说没有人关心你点击空白处是为了干什么。

发布订阅模式应用

class test {
  constructor() {
    this.message = {}; //消息队列
  }

  // 订阅消息
  $on(type, callback) {
    if (!this.message[type]) {
      this.message[type] = [];
    }
    this.message[type].push(callback);
  }
  // 取消订阅
  $off(type, callback) {
    if (!this.message[type]) return;
    if (!callback) {
      this.message[type] = undefined;
      return;
    }
    this.message[type] = this.message[type].filter((item) => item !== callback);
  }
  // 触发事件
  $emit(type) {
    if (!this.message[type]) return;
    this.message[type].forEach((item) => {
      item();
    });
  }
}

JavaScript 设计模式

原型模式

原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式之一,即复制已有的对象来创建新的对象,js中的原型链就与之有关。

这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。

const baseUser = {
    /* ... */
}

const user = Object.create(baseUser)

通过Object.create来创建一个新的对象,新的user对象与baseUser是继承关系,可以在user中进行初始化,这两个对象是相互独立的,不相互影响。

代理模式

  • 在代理模式中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

  • 在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。

应用实例:

  1. Windows 里面的快捷方式。
  2. 猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。
  3. 买火车票不一定在火车站买,也可以去代售点。
  4. 一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制。
const createProxyUser = (name) => {
  const user = new User(name);
  const proxyUser = new Proxy(user, {
    set: (target, prop, value) => {
      target[prop] = value;
      /* ... */
      return true;
    },
  });
};

迭代器模式

在不暴露数据类型的情况下访问集合中的数据

使用场景:

  1. 访问一个聚合对象的内容而无须暴露它的内部表示。
  2. 需要为聚合对象提供多种遍历方式。
  3. 为遍历不同的聚合结构提供一个统一的接口。

前端框架中的设计模式

代理模式

JavaScript中的代理模式不同,与其迭代器模式有些类似。

例如Vue中定义的ref变量,它经过一层编译,当该变量变化时,页面上立刻会渲染出新的数据。

JavaScript我们通常是绑定一个事件,当事件发生时用innerHTML手动去修改页面中的值,后来有了Vue之后,带来了虚拟DOM的环节,对原始的真实DOM做了代理,页面的渲染完全自动化了。

前端代理模式.png

组合模式

组合模式,又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。

这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。

React 的组件结构

export const Count = () => {
    const [const, setCount] = useState(0);
    return {
        <button onClick={() => setCount((count) => count + 1)}>
        	count is: {count}
        </button>
    }
}