这是我参与「第四届青训营 」笔记创作活动的第2天
23种设计模式
- 创建型 - 如何创建一个对象
- 结构型 - 如何灵活的将对象组装成较大的结构
- 行为型 - 负责对象间的高效通信和职责划分
浏览器中的设计模式
单例模式
定义:全局唯一访问对象
应用:缓存,全局状态管理
例子:浏览器中的window
//用单例模式实现请求缓存
//类实现
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;
}
}
//函数式实现
import api from "./utils";
const cache:Record<string,string> = {}
export const request async (url:string)={
if (cache[url])
return cache[url]
}
const response await api(url);
cache[url] = response;
return response;
};
发布订阅模式
定义:一种订阅机制,可在被订阅对象发生变化时通知订阅者
应用场景:从系统架构之间的解耦,到业务中一些实现模式,像邮件订阅,上线订阅等,应用广泛。
如:
const button document.getElementById("button");
const dosomthing1 = () =>console.log("Send message to user");
const doSomthing2 = ()=>console.log("Log...");
button.addEventListener("click",doSomthing1);
button.addEventListener("click",doSomthing2);
//用发布订阅模式实现用户上线订阅
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);
});
}
}
//测试
test("should notify followers when user is online for multiple users",()=>(
const user1 = new User("user1");
const user2 = new User("user2");
const user3 = new User("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);
});
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 multiple users",()=>(
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);
});
代理模式
定义:可自定义控制对原对象的访问方式,并且允许在更新前后作一些额外处理
应用场景:监控,代理工具,前端框架实现等
//使用代理模式实现用户状态订阅
export const createProxyUser(ndme:string)=>{
const user = new User(name);
const proxyUser new Proxy(user,{
set:(target, prop:keyof User, value)=>{ //设置对user的set拦截器
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;
};
迭代器模式
定义:在不暴露数据类型的情况下访问集合中的数据
应用场景:数据结构中有多种数据类型,列表,树等,提供通用操作接口
//例子
const numbers = [1,2,3];
const map = new Map();
map.set("k1","v1");
map.set("k2","v2");
const set = new Set(["1","2","3"]);
for (const number of numbers){
//...
}
for (const [key,value]of map){
//...
}
for (const key of set){
//...
}
//用for...of迭代所有组件
class MyDomElement{
tag:string;
children:MyDomElement[];
constructor(tag:string){
this.tag = tag;
this.children = [];
}
addchildren(component:MyDomELement){
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 }
}
};
}
}
前端框架中的设计模式
代理模式
Vue当中对DOM操作的代理
原本:更改DOM属性 → 试图更新
vue: 更改DOM属性 → 更新虚拟DOM → 视图更新 (包括Diff算法)
具体实现见Vue源码
组合模式
定义:可多个对象组合使用,也可单个对象 独立使用
应用场景:DOM,前端文件,文件目录,部门
例子是React的组件结构
练习题
使用组件模式实现一个文件夹结构
- 每个文件夹可以包含文件和文件夹
- 文件有大小
- 可获取每个文件夹下文件的整体大小