前端应用设计思维提升|青训营笔记

60 阅读6分钟

前端应用设计思维提升|青训营笔记

这是我参与「第四届青训营 」笔记创作活动的的第6天!

浏览器中的设计模式

单例模式

  • 定义:全局唯一访问对象
  • 应用场景:缓存、全局状态管理等。
    这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
    需要注意的是:
  • 单例类只能有一个实例。
  • 单例类必须给自己创建自己的唯一实例。
  • 单例类必须给所有其他对象提供这一个实例。

优点是:

  • 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例。
  • 避免对资源的多重占用。

缺点是:

  • 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。

使用单例模式实现请求缓存代码如下:

import { http } from './utils';
const cache: Record<string, string> = {};
//定义缓存变量
export const request = async (url: string) => {
//封装一个异步请求
    if (cache[url]) {
        return cache[url];
    }
    const response = await http.get(url);
    cache[url] = response;
    return response;
}
//测试
test('should response quickly second time', async () => {
    await request('/user/1');
    const startTime = Date.now();
    await request('/user/1');
    const endTime = Date.now();
    expect(endTime - startTime).toBeLessThan(50);
})

发布订阅模式

  • 定义:一种订阅机制,可在被订阅对象发生变化时通知订阅者。
  • 应用场景:从系统架构之间的解耦,到业务中一些实现模式,像邮件订阅、线上订阅等等,应用广泛。

发布—订阅模式又叫观察者模式,它定义了对象间的一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知。

优点:耦合性低,便于代码的维护

缺点:创建订阅者本身要消耗一定的时间和内存,可能订阅的消息未发生,但这个订阅者会始终存在于内存中 使用发布订阅模式实现请求缓存代码如下:

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

JavaScript中的设计模式

JavaScript中的设计模式有三种:

  • 原型模式
  • 代理模式
  • 迭代器模式。

原型模式

  • 定义:复制已有对象未创建新的对象。
  • 应用场景:JS中对象创建的基本模式。

优点:

  • Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用,可辅助实现撤销操作。

缺点:

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。

使用原型模式创建上线订阅中的用户代码如下:

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

代理模式

  • 定义:可自定义控制原对象的访问方式,并且允许在更新前后做一些额外处理。
  • 应用场景:监控、代理工具、前端框架实现等。

代理模式特点:自定义控制对元的对象访问,并且允许更新前后处理;多用于监控和代理等。

使用代理模式创建上线订阅中的用户代码如下:

type Notify = (uesr: User) => void;
export class User {
    name: string;
    status: "online" | "offline";
    followers: { user: User, notify: Notify }[];
    constructor(name: string) {
        this.name = name;
        this.status = "online";
        this.followers = [];
    }
    subscribe(user: User, notify: Notify) {
        user.followers.push({ user, notify })
    }
    online() {
        this.status = "online";
    }
}
export const createProxyUser = (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" | "offline") => {
        if (status == "online") {
            user.followers.forEach(({ notify }) => notify(user));
        }
    }
    return proxyUser;
}

迭代模式

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

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

    迭代器模式的本质:控制访问聚合对象中的元素。其设计意图:无须暴露聚合对象的内部实现,就能够访问到聚合对象中的各个元素。 迭代模式可以实现隐藏数据类型的访问。适用于复杂数据结构的解析,提供通用操作接口。 常见的有数组、列表、树的混用。

前端框架中的设计模式

组合模式

  • 定义:可对多个对象组合使用,可也单个对象独立使用。
  • 应用场景:DOM、前端组件、文件目录、部门。

组合多个对象形成树形结构以表示“整体-部分”的关系的层次结构。组合模式对叶子节点和容器节点的处理具有一致性,又称为整体-部分模式。

优点:

  • 可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构件也更容易。
  • 客户端调用简单,客户端可以一致的使用组合结构或其中单个对象。
  • 定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。
  • 更容易在组合体内加入对象构件,客户端不必因为加入了新的对象构件而更改原有代码。

缺点:

  • 使设计变得更加抽象,对象的业务规则如果很复杂,则实现组合模式具有很大挑战性,而且不是所有的方法都与叶子对象子类都有关联

个人总结

通过这次课程我学习到了前端设计模式,这个对我个人来说是一个全新的知识,本次课程让我对前端的系统理论有了新的认识,认知到自身的不足,需要努力学习提高自身。