JS设计模式,单例模式、观察者模式、发布订阅模式

297 阅读3分钟

设计模式

 设计模式

           面向对象开发人员在长期开发过程中总结的一套解决特定问方案写法

        设计模式

           23种 三类

        

        单例模式

           整个应用程序中只有一个实例存在

image.png

image.png

image.png

image.png

image.png

单例模式

单例模式(Singleton Pattern)是 最简单常用的设计模式之一。

这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

        单例模式

           整个应用程序中只有一个实例存在
class Person {

				// 创建对象之前先判断它是否存在,如果存在,直接使用,不存在去创建

                // static修饰的方法称为静态方法,直接通过类名调用与实例对象无关

				static getInstance() {

					if (this.instance == null) {

						this.instance = new Person()

					}

					return this.instance

				}

				constructor() {

					this.name = 'jack'

				}

			}



			// 创建对象之前先判断它是否存在,如果存在,直接使用,不存在去创建

			// let p1 = new Person() // jack

			// let p2 = new Person() // jack



			let p1 = Person.getInstance()

			let p2 = Person.getInstance()



			console.log(p1 === p2)

观察者模式

观察者模式,通常也被叫做 发布-订阅模式 或者 消息模式 英文名称叫做 Observer

官方解释: 当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新,解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题

  观察者模式:  研究对象与对象之间关系

            当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新

            例子:

               明星 与 粉丝

               张三  与   小王、 小李、 小丽 

               张三状态发生变化 它的粉丝都可收到通知

            

        如何实现观察模式?

           class 明星类{

               constructor(name){

                   this.list = [] // 存储添加的粉丝对象

                   this.name = name

               }

               // 更新状态功能

               updateState(message){

                   this.list.forEach(obj=>{

                       obj.receieMessage(message)

                   })

               }

               // 添加粉丝功能

               add(obj){

                  this.list.push(obj)

               }



           }



           class 粉丝类{

               constructor(name){

                   this.name = name

               }

               // 接收消息功能

               receiveMessage(msg){

                   console.log(msg)

               }

           }

代码:

 // 明星类 被观察者-主体

        class Star{

            constructor(name) {

                this.name = name

                this.list = [] // 存储粉丝对象

            }

            //添加粉丝对象

            add(obj){

                this.list.push(obj)

            }

            //更新状态

            updateState(message){

                this.list.forEach(obj=>{

                    obj.receive(message)

                })

            }

        }



        // 粉丝类,观察者

        class Observer{

            constructor(name) {

                this.name = name

            }

            // 接收信息

            receive(msg){

                console.log(this.name + '看到信息 '+ msg + ' 很伤心!')

            }

        }



        // 创建明星李,创建粉丝,小丽,小红,小张

        // 李宣布“离开娱乐圈”

        let lyf = new Star('李易峰')

        let xiaoli = new Observer('小丽')

        let xiaoRed = new Observer('小红')

        let xiaozhang = new Observer('小张')



        //关注明星

        lyf.add(xiaoli)

        lyf.add(xiaoRed)

        lyf.add(xiaozhang)



        // 李宣布“离开娱乐圈”

        lyf.updateState('李离开娱乐圈')

发布订阅模式

发布/订阅模式由 订阅者、发布者、信号中心构成

我们假定,存在一个”信号中心”,某个任务执行完成,就向信号中心”发布”(publish)一个信号,其他任务可以向信号中心”订阅”(subscribe)这个信号,从而知道什么时候自己可以开始执行。 这就叫做”发布/订阅模式”(publish-subscribe pattern)

 发布/订阅模式

            发布者  ->   消息事件中心   ->    订阅者

                           不同类型    ->    订阅者



            按钮点击事件

            发布者(点击按钮的人)         

               | 

             事件处理中心 

               |

            订阅者(按钮)



            三部份组成 :

               发布者 : 负责发布消息事件中心 

               订阅者 : 订阅事件处理中心消息

               事件处理中心 : 

                   处理不同类型的消息,发送给不同的订阅者

                   {

                       消息类型: [消息事件1,消息事件2]

                       click: [执行订阅的消息1,执行订阅的消息2],

                       mousemove:[...]

                   }

                   订阅消息

                      向事件对象添加一条数据

                   发布消息

                      触发指定类型消息



            购书

              小明去书店购书,书店没有三国演义本书,小明订阅这本书,当书到达时通知我

              小红啊去书店购书,书店没有西游记本书,小明订阅这本书,当书到达时通知我



              订阅者    事件处理中心         发布者(出版商,书店)

                        购书buybook

                        通知订阅者书到达

代码:

<body>

		<button class="btn1">订阅者1</button>

		<button class="btn2">订阅者2</button>



		<script>

			function test1() {

				const btn1 = document.querySelector('.btn1')

				const btn2 = document.querySelector('.btn2')

				btn1.addEventListener('click', function () {

					console.log('执行订阅的消息1')

				})

				btn2.addEventListener('click', function () {

					console.log('执行订阅的消息2')

				})

			}

            

            // 事件处理中心

            class EventCenter{

                constructor(){

                    //{type:[执行消息处理函数1,执行消息处理函数2...]}

                    this.subs = {}

                }

                //订阅消息

                addEvent(type,even){

                    // if(!this.subs[type]){

                    //     this.subs[type] = []

                    // }

                    this.subs[type] = this.subs[type] || []

                    this.subs[type].push(even)

                }

                // 发布消息

                emitEvent(type){

                    if(this.subs[type]){

                        this.subs[type].forEach(even=>{

                            even()

                        })

                    }

                }

            }



            // let eventCenter = new EventCenter()

            // // 订阅类型为click的事件,

            // eventCenter.addEvent('click',function(){

            //     console.log('执行消息处理函数1');

            // })

            // eventCenter.addEvent('click',function(){

            //     console.log('执行消息处理函数2');

            // })



            // // 发布消息

            // eventCenter.emitEvent('click')





            let eventCenter = new EventCenter()

            eventCenter.addEvent('buybook',function(){

                console.log('你订阅的三国演义书已到');

            })

            eventCenter.addEvent('buybook',function(){

                console.log('你订阅的西游记书已到');

            })



            eventCenter.emitEvent('buybook')

            







        </script>

	</body>