浅识js——设计模式

64 阅读4分钟

一、什么是设计模式?

  • 为了解决某一类问题 的一个优化过的代码解决方案

二、单例模式

  • 一个构造函数,一生只能创建一个实例化对象,(准备一个变量默认赋值为null,然后在第一次实例化的时候给这个变量赋值为实例化对象,后续在调用实例化的时候,就不再创建实例化对象了,而是拿到提前准备好的变量)
    // 单例模式
    class Dialog{
      constructor () {
        console.log('在页面中创建一个弹出层')
      }
    }
    
    let instance = null
    function newDialog () {
      if (instance === null){
          instance = new Dialog
        } 
        return instance
      }

    // 第一次调用 创建一个实例化对象然后给到instance 中,并返回instance
    let d1 = newDialog()
    // 第二次以及后续的所有调用,都直接返回instance
    let d2 = newDialog()
    
    
    // 升级1:原本的instance变量为一个全局变量,本次利用自执行函数与闭包将其及修改为局部变量 
    class Dialog{
      constructor () {
        console.log('在页面中创建一个弹出层')
      }
    }
    const newDialog = (function () {  //自执行函数
      // 自执行函数内 创建一个变量(局部变量)
      let instance = null
      return function () {    //闭包
        if (instance === null){
          instance = new Dialog
        }
        return instance
      }
    }) ()

    const d1 = newDialog()
    const d2 = newDialog()
   
   //升级2
    const Dialog = (function () {
      let instance = null 
    
      class Dialog {
        constructor () {
        this.title = ''
        console.log('在页面中创建一个弹出层')
      }
      setTitle(newTitle) {
        this.title = newTitle
      }
    }
    return function (type) {
      if (instance === null) {
        instance = new Dialog() //当前分支语句的代码 只会在第一次的时候 执行
      }
      instance.setTitle(type)
      return instance
    }
    })()
    
    const d1 = new Dialog('警告')
    console.log(d1)

    const d2 = new Dialog('通用')
    console.log(d2)

二、策略模式

  • 为了解决过多的 if...else的嵌套问题
  • 核心(超时折扣案例):
    • 创建一个数据结构,结果内存储着各种折扣记录,对应的值,是这个折扣的计算方式
   // 策略模式1
    const calcPrice = (function () {
      // 当前对象内存储着各种折扣,以及对应的打折后商品总价的计算方式
      const calcList = {
        '80%' : (total) => { return (total * 0.8).toFixed(2)},
        '70%' : (total) => { return (total * 0.7).toFixed(2)},
      }

      function inner(type, total) {
        // type 表示当前几折
        // total 打折前的商品总价
        // 调用当前函数是要得到打折后的商品总价,所以要写一个return
        return calcList[type](total)
      }

      return inner
    })()
    console.log(calcPrice('80%',200))



    // 策略模式2
    //  js中 所有的引用数据类型,都可以当成一个对象来使用
     const calcPrice = (function () {
      const calcList = {
        '70%' : (total) => { return (total * 0.7).toFixed(2)},
        '80%' : total =>  (total * 0.8).toFixed(2),
        '50%' : total =>  (total * 0.5).toFixed(2)
      }

      function inner(type, total) {
        return calcList[type](total)
      }
      inner.add = function (type, fn){
        calcList[type] = fn
      }
      inner.sub = function (type) {
        delete calcList[type]
      }
      inner.getList = function () {
        return calcList
      }
      return inner
    })()

    console.log(calcPrice('80%',200))
    // 添加一个活动
    calcPrice.add('60%',total => (total * 0.6).toFixed(2))
    // 删除某一项活动
    calcPrice.sub('60%')
    // 查看对象中有哪些数据
    console.log(calcPrice.getList())

三、发布订阅模式

  • 一般处理大型项目(框架)的封装
    /*
       发布订阅模式案例:
          1. 你去到书店, 问店员 有没有一本叫做 <JS 从入门到入土>
          2. 店员: 我们现在没有, 然后你留下一个联系方式, 将来有了之后我电话通知你
          3. 过了一段时间, 有书本了, 店员通过电话联系到你, 触发了你的技能(触发了一个函数) 然后购买了书本
          
      'JS 从入门到入土': [预约者1, 预约2, 预约3],
      '颈椎病的预防': [预约1, 预约2, 预约3]
    */
        class observer {
        constructor(name) {
          this.name = name //店员的名字
          this.msgList = {} //模拟店员的记录手册(书名)
        }
        // 购买不到书本 留下预约方式的时候执行
        add(type,fn) {
          // 此函数可以向this.magList内添加内容,后续方便维护
          if (this.msgList[type] === undefined) {
            // // 当前分支执行, 表明这个 type 是第一次出现
            this.msgList[type] = [] // 在第一次出现的时候, 给它赋值一个空数组, 后续的内容直接 push 到数组内就可以了
          }
          this.msgList[type].push(fn)
        }
        // 书到了 通知预约者来取,并触发他们的技能(函数)
        tri(type) {
          this.msgList[type].forEach(item => item()) //通过传入的type找到对应的属性值,并遍历调用内部的所有函数
        }
        delName(type,fn) {
          //这个方法取消预约,找到对应的联系方式并删除
          this.msgList[type] = this.msgList[type].filter(item => item !== fn)
        }
      } 

      const o1 = new observer('小刚')
      console.log(o1)
      // 书名
      const bookName1 = 'js从入门到入土'
      const bookName2 = '颈椎病的预防'

      // 预约者的技能 (函数)
      const fnA = () => console.log('张三,想购买这本书')
      const fnB = () => console.log('李四,想购买这本书')
      const fnC = () => console.log('王五,想购买这本书')

      // 新增三位预约者
      o1.add(bookName1,fnA)
      o1.add(bookName1,fnB)
      o1.add(bookName1,fnC)

      //中间以为预约者取消预约
      o1.delName(bookName1,fnB) 
      // 书本到了, 通知对应的预约者前来购买
      o1.tri(bookName1)

      console.log('有预约者之后的对象',o1);