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

44 阅读2分钟

1. 什么是设计模式

  • 软件设计中常见问题的解决方案模型
    • 历史经验的总结
    • 与特定语言无关

2. 浏览器中的设计模式

2.1. 单例模式

  • 定义

    • 全局访问唯一对象(如window对象)
  • 应用场景

    • 缓存
    • 全局状态管理等
  • 举例:用单例模式实现请求缓存

import { api } from "./utils";

const cache: Record<stringstring> = {};

export const request = async (url: string) => {
    if (cache[url]) {
        return cache[url];
    }
    
    const response = await api(url);
    
    cache[url] = respons;
    return response;
}

2.2. 发布订阅模式

  • 定义

    • 种订阅机制,可在被订阅对象发生变化时通知订阅者
  • 应用场景

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

type Notify = (user: User) => void;

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

3. JavaScript中的设计模式

3.1. 原型模式

  • 定义

    • 复制已有对象来创建新的对象
  • 应用场景

    • JS中对象创建的基本模式
  • 举例:用原型模式创建上线订阅中的用户

const baseUser: User = {
    name: "",
    status: "offline",
    followers: [],
    
    subscribe(user,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;
    user.followers = [];

    return user;
}

3.2. 代理模式

  • 定义

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

    • 监控
    • 代理工具
    • 前端框架实现等等
  • 举例:使用代理模式实现用户状态订阅

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;
}

3.3 迭代器模式

  • 定义

    • 在不暴露数据类型的情况下访问集合中的数据
  • 应用场景

    • 数据结构中有多种数据类型,列表,树等,提供通用操作接口
  • 举例:用for of迭代所有组件

class MyDomElement {
    tag: string;
    children: MyDomELement[];
    
    constructor(tag: string) {
        this.tag = tag;
        this.children = [];
        
    addChildren(component: MyDomETement) {
        this.children.push(component);
    }   
        
    [Symbol.iterator]() {
        const list = [...this.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 }
            }
        }
    }
}

4. 前端框架中的设计模式

4.1. 代理模式

4.2. 组合模式

  • 定义

    • 可多个对象组合使用,可也单个对象独立使用
  • 应用场景

    • DOM
    • 前端组件
    • 文件目录
    • 部门

5. 总结

  • 设计模式不是银弹
    • 总结出抽象的模式相对比较简单,但是想要将抽象的模式套用到场景中却非常困难

    • 现代编程语言的多编程范式带来的更多可能性

    • 真正优秀的开源项目学习设计模式并不断实践