发展背景
模式语言:城镇,建筑,建造
设计模式: 可复用面向对象软件的基础
设计模式分类
- 创建型-如何创建一个对象
- 结构性-如何灵活的将对象组装成较大的结构
- 行为型-负责对象间的高效通信和职责划分
浏览器中的设计模式
- 单例模式
- 发布订阅模式
单例模式
定义:全局唯一访问对象
应用场景:缓存,全局状态管理
单例模式实现请求缓存
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>
组合模式
定义:可多个对象组合使用,也可单个对象使用
应用场景:DOM,前端组件,文件目录,部门
React代码
export const Count = () => {
const [count, setCount] = useState(0);
return <button onClick={() => setCount((count)=>count+1)}>
count is:{count}
</button>;
};