前端设计模式 | 青训营

492 阅读3分钟

发展背景

模式语言:城镇,建筑,建造

设计模式: 可复用面向对象软件的基础

设计模式分类

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

浏览器中的设计模式

  • 单例模式
  • 发布订阅模式

单例模式

定义:全局唯一访问对象

应用场景:缓存,全局状态管理

单例模式实现请求缓存

import { api } from "../../../utils/API";
const cache: Record<string, string> = {};
export const request = async (url: string) => {
  if (cache[url]) {
    return cache[url];
  } else {
    const res = await api(url);
    cache[url] = res;
  }
};

发布订阅模式

定义:一种订阅机制,可在被订阅的对象发生变化时,通知订阅者

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

demo

type Notify = (user: User) => void;
export class User {
  name: string;
  status: "offine" | "online" = "offine";
  follower!: { user: User; notify: Notify }[];
  constructor(name: string) {
    this.name = name;
    this.status = "offine";
    this.follower = [];
  }
  subscribe(user: User, notify: Notify) {
    user.follower.push({ user, notify });
  }
  online() {
    this.status = "online";
    this.follower.forEach(({ notify }) => {
      notify(this);
    });
  }
}

JavaScript中的原型模式

发布订阅模式

定义:复制原来已有的对象来创建新的对象

应用场景:JS中对象创建的基本模式

在原型模式中创建上线订阅中的用户,在ES6之前,没有class那么是如何创建的呢

(() => {
  type Notify = (user: User) => void;
  type User = {
    name: string;
    status: "offline" | "online";
    followers: { user: User; notify: Notify }[];
    subscribe: (user: User, notify: Notify) => void;
    online: () => void;
  };
  const baseUser: User = {
    name: "",
    status: "offline",
    followers: [],
    subscribe(user, notify) {
      this.followers.push({ user, notify });
    },
    online() {
      this.status = "online";
      this.followers.forEach(({ notify }) => {
        notify(this);
      });
    },
  };
  const createUser = (name: string) => {
    const user: User = Object.create(baseUser);
    user.name = name;
    user.followers = [];
    return user;
  };
})();


代理模式

定义:可以自定义控制对原对象的访问方式,并且允许在更新前后做一些额外的处理

应用场景:监控,代理工具,前端框架实现等等

使用代理模式给发布订阅添加功能

type Notify = (user: User) => void;
class User {
  name: string;
  status: "offine" | "online" = "offine";
  follower!: { user: User; notify: Notify }[]; //订阅者
  constructor(name: string) {
    this.name = name;
    this.status = "offine";
    this.follower = [];
  }
  //订阅此用户
  subscribe(user: User, notify: Notify) {
    user.follower.push({ user, notify });
  }
  //发布订阅
  online() {
    this.status = "online";
  }
}
export const createProxy = (name: string) => {
  const user = new User(name);
  const proxyuser = new Proxy(user, {
    set: (target, prop: keyof User, value) => {
      target[prop] = value;
      if (prop === "status") {
        notifyStatusHandlers(target, value);
      }
      return true;
    },
  });
  const notifyStatusHandlers = (user: User, status: "online" | "offine") => {
    if (status === "online") {
      user.follower.forEach(({ notify }) => {
        notify(user);
      });
    }
  };
  return proxyuser;
};

迭代器模式

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

应用场景:数据结构有多种数据类型,列表,数等,提供通用的操作接口

class MydomElement {
  tag: string;
  children: MydomElement[];
  constructor() {
    this.children = [];
    this.tag = "";
  }
  addchildren = (chile: MydomElement) => {
    this.children.push(chile);
  };
  [Symbol.iterator]() {
    const list = [...this.children];//复制children
    let node;//迭代变量
    return {
      next: () => {
      //深度优先遍历,遍历出所有子节点
        while ((node = list.shift())) {
          node.children.length > 0 && list.push(...node.children);
          return { value: node, done: false };
        }
        return { value: null, done: true };
      },
    };
  }
}

前端框架中的设计模式

代理模式

Vue实现计数器

<template>
     <Button @click="count++">count:{{count}}</Button>
</template>
<script setup lang="ts">
   import { ref} from 'vue';
   const count = ref(0);
</script>

image.png

组合模式

定义:可多个对象组合使用,也可单个对象使用

应用场景:DOM,前端组件,文件目录,部门

React代码

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