常见的设计模式
这是我参与「第四届青训营」笔记创作活动的的第6天!
一、单例模式
浏览器中常见的window对象,在整个浏览器渲染环境中,只保证只有一个实例,作为全局的共享对象
二、发布订阅者模式
订阅者向被订阅者注册回调函数,当被订阅者状态变更时,调用订阅者的回调函数,实现发布的效果
小案例:
① 订阅者
调用订阅方法
时传入订阅者对象
: {被订阅者对象
, 订阅者回调函数
} => 即往被订阅者
中的follower
中Push入订阅者的对象
;
② 当被订阅者状态变更
时,执行所有的被订阅者follower
中的订阅者注册的回调函数
type Notify = (user: User) => void
class User {
name: string
status: 'online' | 'offline'
follower: {user: User, notify: Notify}[]
constructor (name: string) {
this.name = name
this.status = 'offline'
this.follower = []
}
subscribe (user: User, notify: Notify) {
user.follower.push({ user, notify })
}
online () {
this.status = 'online'
this.follower.forEach(({ notify }) => {
notify(this)
})
}
offline () {
this.status = 'offline'
this.follower.forEach(({ notify }) => {
notify(this)
})
}
}
const lzx = new User('lzx')
const xmd = new User('xmd')
const cjt = new User('cjt')
lzx.subscribe(cjt, () => {
console.log('LZX:')
if (cjt.status == 'online') console.log('jt来了, 嘿嘿')
if (cjt.status == 'offline') console.log('jt走了, 呜呜')
})
xmd.subscribe(cjt, () => {
console.log('XMD:')
if (cjt.status == 'online') console.log('jt来了, 嘿嘿')
if (cjt.status == 'offline') console.log('jt走了, 呜呜')
})
cjt.online()
console.log('-------')
cjt.offline()
三、原型模式
通过复制对象创造一个新的对象,在新对象上设置值
四、代理模式
能够在变成对象前后,进行一些其他的操作,实现一些解耦性的操作,上述案例使用如下代理:
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') {
notifyStatusHandle(target, value)
}
return true
}
})
const notifyStatusHandle = (user: User, status: String) => {
if (status === 'online' || 'offline') {
user.follower.forEach(({notify}) => {
notify(user)
})
}
}
return ProxyUser
}
前面实现的方式,对状态的变更和消息的发布的业务耦合在一起,没有体现单一职责原则
(一个方法只做一件事情),使用代理模式实现status变更时,再进行消息的发布调用,往后我们要做别的业务嵌入,也只需要在代理对象中加入我们的别的对象
五、迭代器模式
在类中,有一个内置属性[Symbol.iterator]
,其作为一个函数,返回值是一个包含next方法的对象,此操作可以给class加上迭代属性,从而在for…of循环中取值
- 每次调用next方法,都会返回当前成员的结构信息。具体来说就是包含了value和done两个属性的对象,其中value是当前成员的值,done表示遍历是否完成
class MyItertor {
name = 'LZX'
pets = ['cat', 'dog', 'bird', 'fish'];
[Symbol.iterator]() {
let node
return {
next: () => {
while(node = this.pets.shift()) {
return {value: node, done: false}
}
return {value: null, done: true}
}
}
}
}
const iterator = new MyItertor()
for(let item of iterator) {
console.log(`${iterator.name} have a ${item}.`)
}
六、前端框架中的设计模式
代理模式:
- 前端框架中对DOM操作的代理
- DOM更新前后,onBeforeUpdate() + onAfterUpdate(),是用的代理模式
组合模式:
- 多个对象组合成为单个对象,也可单个对象单独使用
- DOM结构,前端组件,文件目录