什么是设计模式
设计模式是解决方案模型
一共有23种设计模式,分为三大类型
- 创建型,如何创建一个对象
- 结构型,如何灵活的将对象组装成较大的结构
- 行为型,负责对象间的高效通信和职责划分
浏览器中的设计模式一般有以下两种
- 单例模式
- 发布订阅模式
其中,单例模式属于创建型,发布订阅模式属于行为型
单例模式
- 定义:全局唯一访问对象
- 应用场景:缓存,全局状态管理等
用单例模式实现请求缓存
单例模式是指类只有一个实例,一般会将这个实例放在类里, 只能通过类里的方法访问
- 创建: 在类的内部创建,如果创建过就返回之前创建的实例
- 访问: 提供一个公共的静态方法来访问实例(优点:可以限制单例对象的访问权限)
用传统的面向对象的思维实现单例模式
创建一个类,类里有一个static类型的变量用于存储该类的唯一实例,在类的外部不能通过new关键字创建对象,要获取该对象的唯一实例只能通过其中的静态方法getInstance, 该方法会判断唯一实例是否存在,存在则返回已经存在的实例,不存在则会new一个实例并赋值给类中instance变量
// 用class 实现单例模式
import { api } from "./utils"
export class Requset {
static instance: Request // instance用于保存单例
private cache: Record<string, string>
// 构造函数,在创建实例的时候初始化一个cache用于存储缓存的内容
constructor() {
this.cache = {}
}
// 获取单例
static getInstance() {
if(this.instance) return this.instance
this.instance = new Request()
return this.instance
}
// 缓存url及其响应结果
public async request(url: string){
// 判断是否缓存
if(this.cache[url]){
return this.cache[url]
}
const response = await api(url)
this.cache[url] = response
return response
}
}
// 使用Request缓存响应以及读取缓存结果
test("should response more than 500ms with class", async () => {
// 获取单例,如果单例存在返回,不存在在类内部new一个
const request = Request.getInstance()
const startTime = Date.now()
await request.request("/user/1")
const endTime = Date.now()
const costTime = end - startTime
expect(costTime).toBeGreaterThanOrEqual(500)
})
test("should response quickly second time with class", async () => {
// 获取单例,如果单例存在返回,不存在在类内部new一个
const request1 = Request.getInstance()
await request1.request("/user/1")
const startTime = Date.now()
const request2 = Requset.getInstance() // request1和request2 是同一个实例
await request2.request("/user/1")
const endTime = Date.now()
const costTime = end - startTime
expect(costTime).toBeLessThan(50)
})
用Javascript特有的语法模式实现单例模式
在传统的面向对象语言中,不能直接export一个方法,所以一定要创建一个类,并在类中new一个对象,通过export一个类,并通过类中的方法得到单例对象
而在javascript 中,一个module可以直接运用export去向外提供模块中的一个方法,因此单例模式可以简化成如下的形式
import { api } from "./utils"
const cache: Record<string, string> = {}
export const request = async (url: string) = {
if(this.cache[url]){
return this.cache[url]
}
const response = await api(url)
this.cache[url] = response
return response
}
发布订阅模式
- 定义:一种订阅机制,可以在被订阅对象发生变化时通知订阅者
- 应用场景:从系统架构之间的解耦,到业务中一些实现模式,如邮件订阅,上线订阅等
用发布订阅模式实现用户上线订阅
发布订阅模式涉及订阅者和被订阅者,在前端中因为函数可以作为参数传递,所以订阅者也可以是一个函数
在以下的例子中,User代表发布者对象,通过 subscribe 方法来订阅特定的事件名称和相应的回调函数。当状态改变时,通过 online 方法来发布对应的事件,并传递相关的数据给订阅者的回调函数。
type Notify = (user:User) => void // 订阅者(订阅者也可以是一个函数)
export class User {
name:string
status: "offline" | "online"
followers: {user: User; notify: Notify}[] // 存储不同的user对应的回调函数(订阅)
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()
// 订阅user3
user1.subscribe(user3, mockNotifyUser1)
user2.subscribe(user3, mockNotifyUser2)
// 发布,通知(执行)mockNotifyUser1和mockNotifyUser2
user3.online()
expect(mockNotifyUser1).toBeCalledWith(user3)
expect(mockNotifyUser2).toBeCalledWith(user3)
})