软件设计中常见问题的解决方案模型 | 青训营笔记

68 阅读3分钟

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

设计模式是开发⼈员在开发过程中⾯临的⼀般问题的解决⽅案。这些解决⽅案是众多软件开发⼈员经过相当长的⼀段时间的试验和错误总结出来的。

设计模式是⼀套被反复使⽤的、多数⼈知晓的、经过分类编⽬的、代码设计经验的总结。使⽤设计模式是为了重⽤代码、让代码更容易被他 ⼈理解、保证代码可靠性。

项⽬中合理地运⽤设计模式可以完美地解决很多问题,每种模式在现实中都有相应的原理来与之对应,每种模式都描述了⼀个在我们周围不 断重复发⽣的问题,以及该问题的核⼼解决⽅案,这也是设计模式能被⼴泛应⽤的原因。

软件设计中常见问题的解决方案模型

  • 历史经验总结
  • 与特定语言无关

23种设计模式

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

浏览器中的设计模式

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

单例模式 定义:全局唯一访问对象 应用场景:缓存,全局状态管理、

用单例模式实现请求缓存

import { api } from "./utils";
export class Requset {
    static instance: Requset;
    private cache: Record<string, string>;

    constructor() {
        this.cache = {};
    }
    static getInstance() {
        if (this.instance) {
            return this.instance;
        }
        this.instance = new Requset();
        return this.instance;
    }
    public async request(url: string) {
        if (this.cache[url]) {
            return this.cache[url];
        }
        const response = await api(url);
        this.cache[url] = response;

        return response;
    }
}

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

const button = document.getElementById("button");

const doSomthing1 = () => {
    console.log("send message to user");
};
const doSomthing2 = () => {
    console.log("Log... ");
};
//button 被订阅对象   函数 订阅者
button.addEventListener("click", doSomthing1); 
button.addEventListener("click", doSomthing2);

JavaScript中的设计模式

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

原型模式 定义:复制已有对象来创建新的对象 应用场景: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;
};

使用:

test("should notify followers when user is online for user prototypes", () => {
    const user1 = createUser("user1");
    const user2 = createUser("user2");
    const user3 = createUser("user3");

    const mockNotifyUser1 = jest.fn();
    const mockNotifyUser2 = jest.fn();

    user1.subscribe(user3, mockNotifyUser1);
    user2.subscribe(user3, mockNotifyUser2);

    user3.online();

    expect(mockNotifyUser1).toBeCalledWith(user3);
    expect(mockNotifyUser2).toBeCalledwith(user3);
});

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

迭代器模式 定义:在不暴露数据类型的情况下访问集合中的数据 应用场景:数据结构中有多种数据类型,列表,树中等,提供通用操作接口

前端框架中的设计模式

  • 代理模式
  • 组合模式

Vue组件实现计数器

前端框架中对DOM操作的处理

没有框架之前通过更改DOM属性然后手动操作视图更新(innerHTML) 在新的框架中,我们看似是在更改一个DOM属性,但我们操作的DOM都是代理过后的DOM(虚拟DOM),跟真正的DOM会有一些diff的操作,然后自己去做对应的视图更新

DOM更新前后的钩子

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