js常用的几种设计模式

js常用的几种设计模式

设计模式就是针对特定问题,给出的简洁而优化的处理方案

常用的设计模式

  • 单例模式
  • 组合模式
  • 观察者模式

1. 单例模式

  • 单例模式就是,使构造函数只有一个实例对象,也就是一个构造函数只能new出一个对象
  • 单例模式的核心代码
<script>
    function Person(){
        this.name='Jack'
    }
    //全局
    var instance=null;
    function singleton(){
        if(instance===null){
            instance=new Person()
        }
        return instance
    }
    /*
        singleton第一次调用
            =>if条件判断,判断instance===null
            =>singleton自己的作用域里面没有instance,就到父级作用域访问
            =>到父级作用域(全局作用域)拿到了instance
            =>现在全局的instance就是一个null,if条件为true
            =>给nstance赋值一个Person的实例(实例001)
            =>现在全局的instance的值就是实例001
            =>return instance就是return实例001
            =>p1得到的就是实例001
    */
      var p1=singleton()
    
    /*
        singleton第二次调用的时候
            =>if条件判断,判断instance===null
            =>singleton自己的作用域里面没有instance,就到父级作用域访问
            =>到父级作用域(全局作用域)拿到了instance
            =>现在全局的instance就是一个实例001
            =>if条件不满足,代码不执行
            =>return instance就是return实例001
            =>p2得到的依旧是实例001
    */
    var p2=singleton()
    //p1和p2得到的都是第一次执行的时候的实例,p1和p2是同一个地址
    console.log(p1===p2)//true
<script/>
  • 单例模式的作用
    如果构造函数生成的实例化对象、属性、功能、方法都相同,就生成一个实例化对象

2. 单例模式

  • 组合模式就是把几个构造函数的入口函数组合在一起,然后使用一个‘遥控器’进行统一调用
  • 实现组合模式
    需要一个数组来存放所有构造函数的实例
    需要一个方法,往数组里面添加内容
    需要一个方法,来启动数组里面的 所有内容
  • 组合模式的作用
    通过一个方法,控制多个构造函数的执行

3. 观察者模式

  • 观察者模式也称发布/订阅模式或者消息模式
  • 作用
    主体数据改变,通知其他相关个体,作出相应的数据更新
  • 从两个角度分析观察者模式
观察者角度(观察者和发布/订阅这两个是一个设计模式)
  • 观察者:就像学校管理学生一样,有班主任、年级主任、教务主任,他们都有一个共同的技能就是请家长。他们就是在暗中观察学生的人,一旦学生做的事情违反了校纪校规,就会触发他们请家长的技能
  • 被观察者:学生就是被观察者,学生的状态就是好好学习,一旦学生的状态改变为早恋,立马就会通知正在观察学生的观察者,观察者就会触发他们的技能
  • 目的:让观察者看着被观察者,只要数据改变了,就让观察者做一些事情
  //准备两个构造函数
        //1.被观察者(学生)
        class Student{
            constructor(){
                //学生本身的状态,就是好好学习
                this.state='好好学习'

                //准备一个数组,存放观察学生的观察者
                //一旦学生的状态从好好学习变成早恋的时候,就让这个数组里面的所有老师触发技能

                this.observers=[]
            }

            //方法
            //1.可以改变状态的方法
            setState(value){
                
                //可以改变状态
                this.state=value
                //状态一旦改变,就要通知观察者
                this.notify()
            }
            
            //2.获取状态
            getState(){
                return this.state
            }

            //3.添加观察者

            //往this.observers里面追加一个观察者
            attach(observer){
                this.observers.push(observer)
            }

            //4.通知this.observers数组里面的每一个观察者,学生状态改变了
            notify(){
                this.observers.forEach(item => item.qingjiazhang(this.state))
            }
        }

        //2.观察者(老师)
        class Observer{
            constructor(name){

                //标明观察者是班主任还是年级主任还是教务主任
                this.name=name
            }

            //方法,就是老师能触发的技能
            qingjiazhang(state){
                console.log(`我是${this.name},因为你${state}了,我要请你家长来!`);
            }
        }
        var xiaoming=new Student();//被观察者

        //观察者
        var banzhuren=new Observer('班主任');
        var nianjizhuren=new Observer('年级主任');
        var jiaowuzhuren=new Observer('教务主任');

        //让班主任看着小明
        xiaoming.attach(banzhuren);
        //让年级主任看着小明
        xiaoming.attach(nianjizhuren);
        //让教务主任看着小明
        xiaoming.attach(jiaowuzhuren);
        //当小明状态改变的时候,xiaoming.setState()就能改变小明现在的状态
        //就触发xiaoming.notify()
        //就会把xiaoming.observers这个数组里面的每一名老师的请家长技能调用
        xiaoming.setState('早恋');//对象调用方式
发布/订阅角度(观察者和发布/订阅是两个设计模式)
  • 分三个状态
    订阅
    取消订阅
    发布
  • 发布/订阅需要的内容
    1. 消息盒子(click:[fn1,fn2,fn3] mouseover:[fn4,fn5,fn6])
    2. 订阅的方法(往消息盒子里面添加内容)
    3. 取消订阅的方法(把已经订阅的方法从消息盒子内部拿走)
    4. 发布事件的方法(把消息盒子里面对应的处理函数执行了)
      例子:买书
      我想要买一本《不曾孤独,怎会懂得》的书,我去到书店找,书店没有,我就店员说一声,等有了就打电话通知我=>订阅事件
      我在家等店员的通知,一旦书店到货,店员就给我打电话 =>店员发布事件
      在等待期间,朋友就送了我这本书,我就告诉店员,我不需要这本书了,不用打电话给我了=>取消订阅事件
class Observer{
            constructor(){
                //1.准备消息盒子
                this.message={}
            }

            //2.订阅的方法
            on(type,fn){
                //往消息盒子里面添加内容
                //type是事件类型,你要订阅的类型
                //fn是事件处理函数,你要给这个类型订阅一个什么行为

                //假设现在的type==='click'
                //消息盒子里面就应该是{click:[handlerA]}

                //如果消息盒子里面没有click这个成员,那么就创建这个成员是一个空数组,然后添加进去
                //如果消息盒子里面有这个click成员,那么就直接push

            if(!this.message[type]){
                //表示this.message里面没有这个成员
                this.message[type]=[]
            }
            this.message[type].push(fn)
            }

            //3.取消订阅的方法
            off(type,fn){
                //删除消息盒子里面的某一个成员
                //type是要取消的事件类型,fn是要取消的事件处理函数
                //先看看有没有这个事件类型,如果没有,不需要取消,有才需要取消
                if(!this.message[type]) return

                
                //this.message[type]是一个数组,取消这个数组里面和fn一样的事件处理函数
                //使用数组常用方法filter
                this.message[type]=this.message[type].filter(item =>item !== fn)
                //this.message[type]=this.message[type].filter(function(item){
                    //return item !==fn;
                //})
            }

            //4.发布的方法
            emit(type,...arg){//arg=>arguments

                //执行消息盒子里面某一个对应的处理函数
                //type就是要触发的事件类型
                //判断有没有订阅过,如果没有订阅过,就直接return
                if(!this.message[type]) return
                //组装一个事件对象
                var event={
                    type:type,
                    //参数
                    data:arg
                }

                //调用每一个事件处理函数的时候,都带上一个事件对象
                this.message[type].forEach(item =>item(event))
                
            }
        }

        //将来需要使用的时候
        var o=new Observer()

        //订阅事件
        o.on('click',handlerA)
        o.on('click',handlerB)
        o.on('click',handlerC)
        //发布的事件
        o.emit('click','hello world',100,true,{name:'Jack'})
        
        //事件处理函数
        function handlerA(e){console.log('我是事件处理函数handlerA',e)}
        function handlerB(e){console.log('我是事件处理函数handlerB',e)}
        function handlerC(e){console.log('我是事件处理函数handlerC',e)}
        function handlerD(e){console.log('我是事件处理函数handlerD',e)}
        function handlerE(e){console.log('我是事件处理函数handlerE',e)}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值