设计模式-1

41 阅读1分钟

观察者模式

主体调用方法来增删观察者,并且主动调用观察者的方法

实现主体观察者的绑定功能主要由主体实现,而重点功能实际上在观察者的方法中

先触发的是主体,然后主体通知观察者

观察者模式可以实现面包屑功能

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,详情参考