• 设计模式 --kkb


    设计模式概念

    前人总结的代码最佳实践。

    设计模式是一套被反复使用、多人知晓的、经过分类的、代码设计经验的总结。

    工程师基础(内力,决定走多远)

    算法和数据结构、设计模式、网络协议(TCP/IP 通信 缓存)、操作系统、计算机组成、数据库(和数据结构也息息相关,红黑树)、编译原理(vue的compile模块)

    订阅/发布模式(观察者模式)

    class Event{
      constructor(){
        this.callbacks = {}
      }
      $on(name, fn){ // 监听
        // if(!this.callbacks[name]){
        //   this.callbacks[name] = []
        // }
        // this.callbacks[name].push(fn)
    
        // 上述代码的简写
        (this.callbacks[name] || (this.callbacks[name]=[])).push(fn)
      }
      $emit(name, arg){
        const cbs = this.callbacks[name]
        if(cbs){
          cbs.forEach(c=>{
            c.call(this, arg)
          })
        }
      }
      $off(name){
        this.callbacks[name] = null
      }
    }
    
    let event = new Event()
    event.$on('event1', arg => {
      console.log('event1触发', arg)
    })
    event.$on('event1', arg => {
      console.log('又一个event1触发', arg)
    })
    event.$on('event2', arg => {
      console.log('event2触发', arg)
    })
    
    event.$emit('event1', 'myArg')
    event.$emit('event2', 'myArg2')
    event.$off('event1')
    event.$emit('event1', 'myArg')

    单例模式

    定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点。实现的方法为先判断实例存在与否,如果存在则直接返回,如果不存在就创建了再返回,这就确保了一个类只有一个实例对象。

    适用场景:一个单一对象。比如:弹窗,无论点击多少次,弹窗只应该被创建一次,实现起来也很简单,用一个变量缓存即可

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
      <style>
        .modal{
          position: fixed;
          border: 2px solid red;
          width: 300px;
          height: 300px;
          top: 30%;
          left: 50%;
          margin-left: -150px;
          text-align: center;
          padding: 20px;
        }
      </style>
    </head>
    <body>
      <div id="model-btn">点我</div>
    
      <script>
        function getSingle(fn){
          // 使用闭包存储期望的单例实例
          // 把函数fn变成单例
          let result
          return function(){
            return result || (result=fn.apply(this, arguments))
          }
        }
        function createModalLayer(){
          console.log('新建弹窗')
          // 期望弹窗是全局唯一的
          let div = document.createElement('div')
          div.innerHTML = '我是一个弹窗'
          div.className = 'modal'
          div.style.display = 'none'
          div.addEventListener('click', function(){
            div.style.display = 'none'
          }, false)
          document.body.appendChild(div)
          return div
        }
    
        // 只需要对原本的函数包一层,就变成单例了
        createModalLayer = getSingle(createModalLayer)
    
        document.getElementById('model-btn').addEventListener('click', function(){
          // 新建一个弹窗
          const modalLayer = createModalLayer()
          // 修改弹窗的内容
          modalLayer.style.display = 'block'
          modalLayer.innerHTML = '登录' + new Date()
        }, false)
      </script>
    </body>
    </html>

    策略模式

    // 判断绩效:绩效S为4倍工资,A为3倍工资,B为2倍工资
    
    function calculate(level, salary){
      if(level==='S'){
        return salary*4
      }
      if(level==='A'){
        return salary*3
      }
      if(level==='B'){
        return salary*2
      }
      return salary
    }

    上述代码如果想加入新的条件,比如: SS绩效 5倍工资

    就得多加一条 if 判断

    if(level==='SS'){
      return salary*5
    }

    这种我们称为面条代码,不好维护而且阅读起来比较困难

    将至改造成策略模式(策略 + 使用)

    // 新的策略,就扩展这个对象---这里可以使用配置 {"S":4, "A":3, "B":2} ,也可以是接口返回
    const policy = {
      'S': function(salary){
        return salary * 4
      },
      'A': function(salary){
        return salary * 3
      },
      'B': function(salary){
        return salary * 2
      }
    }
    
    // 使用层(业务层)
    function calculate(level, salary){
      return policy[level] ? policy[level](salary) : salary
    }

    代理模式

    代理模式的定义:为一个对象提供一个代用品或占位符,以便控制对它的访问。

    常用的虚拟代理形式:某一个花销很大的操作,可以通过虚拟代理的方式延迟到这种需要它的时候采取创建(例:使用虚拟代理实现图片懒加载)

    图片懒加载的方式:先通过一张loading图占位,然后通过异步的方式加载图片,等图片加载好了再把完成的图片加载到img标签里面

    原本的代码:

    // 图片实例有一个setSrc方法,会先设置loading,然后再显式图片
    let imgFunc = (function(){
      let imgNode = document.createElement('img')
      document.body.appendChild(imgNode)
      return {
        setSrc: function(src){
          imgNode.src = src
        }
      }
    })()
    
    imgFunc.setSrc('https://res.kaikeba.com/other/123/20191209112316-88923/FvFBVu8ZVu5aLU6yWTvGn8dwrjhm.png')

    使用代理后

    // 图片实例有一个setSrc方法,会先设置loading,然后再显式图片
    let imgFunc = (function(){
      let imgNode = document.createElement('img')
      document.body.appendChild(imgNode)
      return {
        setSrc: function(src){
          // 图片较大时会比较耗时
          imgNode.src = src
        }
      }
    })()
    
    // 使用代理模式,增加loading的功能
    let proxyImage = (function(){
      let img = new Image()
      img.onload = function(){
        // onload加载完毕,再设置
        imgFunc.setSrc(this.src)
      }
      return {
        setSrc(src){
          // 先设置loading
          imgFunc.setSrc('./loading.jpg')
          img.src = src
        }
      }
    })()
    // 使用proxyImage代理操作,设置src
    proxyImage.setSrc('https://res.kaikeba.com/other/123/20191209112316-88923/FvFBVu8ZVu5aLU6yWTvGn8dwrjhm.png')

    中介者模式

    定义:通过一个中介者对象,其他所有的相关对象都通过该中介者对象来通信,而不是相互引用,当其中一个对象发生改变时,只需要通知中介者对象即可。通过中介者模式可以解除对象与对象之间的紧耦合关系。

    适用的场景:例如购物车需求,存在商品选择表单、颜色选择表单、购买数量表单等待,都会触发change事件,那么可以通过中介者来转发处理这些事件,实现各个事件间的解耦,仅仅维护中介者对象即可。

    redux,vuex都属于中介者模式的实际应用,我们把共享的数据,抽离成一个单独的 store,每个都通过 store 这个中介来操作对象。

    装饰器模式

    1

  • 相关阅读:
    Python 循环嵌套
    python 通过序列索引迭代
    Python for 循环语句
    python 无限循环
    Python 循环语句
    Python 条件语句
    Python运算符优先级
    Python身份运算符
    Python成员运算符
    Python逻辑运算符
  • 原文地址:https://www.cnblogs.com/haishen/p/12022568.html
Copyright © 2020-2023  润新知