观察者模式
主体调用方法来增删观察者,并且主动调用观察者的方法
实现主体与观察者的绑定功能主要由主体实现,而重点功能实际上在观察者的方法中
先触发的是主体,然后主体通知观察者
观察者模式可以实现面包屑功能
class Subject{
constructor() {
this.observers=[]
}
add(observer){
this.observers.push(observer)
}
remove(observer){
this.observers = this.observers.filter(itme=>itme!==observer)
}
notify(){
this.observers.forEach(item=>{
item.update()
})
}
}
class Observer{
constructor(name) {
this.name=name
}
update(){
console.log(this.name)
}
}
const subject = new Subject()
const observer1 = new Observer('22')
const observer2 = new Observer('33')
subject.add(observer1)
subject.add(observer2)
subject.notify()
subject.remove(observer1)
setTimeout(()=>{
subject.notify()
},1000)
观察者模式实现面包屑
在面包屑案例中,左边列表都是主体,而右边的面包屑是观察者
成功的将多对多的事件,通过函数传参,变成了一对多的事件,降低了耦合度
但是要注意add观察者,代码才能生效
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
.box{
display: flex;
height: 500px;
}
.box .left{
width: 150px;
background-color: aqua;
}
.box .right{
flex: 1;
background-color: azure;
}
</style>
<body>
<div class="box">
<div class="left">
<div class="label">label</div>
<ul>
<li>首页</li>
<li>部门管理</li>
<li>新闻管理</li>
<li>站点管理</li>
</ul>
</div>
<div class="right">
<div class="bread"></div>
</div>
</div>
</body>
<script>
class Subject{
constructor() {
this.observers=[]
}
notify(data){
this.observers.forEach(item=>{
item.changeText(data)
})
}
add(observer){
this.observers.push(observer)
}
}
class Observe{
constructor(name) {
this.domObject=document.querySelector(name)
}
changeText(data){
this.domObject.innerHTML=data
}
}
const subject = new Subject()
const observe1 = new Observe('.bread')
const observe2 = new Observe('.label')
subject.add(observe1)
subject.add(observe2)
const lis=document.querySelectorAll('li')
lis.forEach(item=>{
item.addEventListener('click',function (){
subject.notify(this.innerHTML)
})
})
</script>
</html>
发布订阅模式
观察者模式中主体和观察者相互知道
发布订阅模式发布者和订阅者通过第三方调度,是经过解耦的观察者模式
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
</body>
<script>
//PubSub 中介
const PubSub = {
message:{},
publish(type,data){
//这个data又可以传给message中的函数了
if (!this.message[type]){
return
}
else {
this.message[type].forEach(item=>item(data))
}
},
subscribe(type,cb){
//有则加之,无则新建
if (!this.message[type]){
this.message[type] = []
this.message[type].push(cb)
}
else {
this.message[type].push(cb)
}
},
unsubscribe(type,cb) {
if (!this.message[type]){
return
}
if (!cb){
//如果没传第二个参数,则取消type下所有的
this.message[type]=[]
}
else {
this.message[type] = this.message[type].filter(item=>item!==cb)
}
}
}
function testA1(data){
console.log('testA1',data)
}
function testA2(data){
console.log('testA2',data)
}
function testB(data){
console.log('testB',data)
}
//订阅
PubSub.subscribe('A',testA1)
PubSub.subscribe('A',testA2)
PubSub.subscribe('B',testB)
//发布
PubSub.publish('A',111)
PubSub.publish("B",222)
console.log(PubSub.message)
PubSub.publish("A",1212)
//解除订阅
PubSub.unsubscribe('A',testA1)
console.log(PubSub.message)
PubSub.unsubscribe('A')
console.log(PubSub.message)
</script>
</html>
在调试这段代码时发现了很有意思的bug,详情参考