设计模式:一种书写代码的方式,为解决特定问题给出的简介而优化的解决方案

1. 单例模式

  1. /*
  2. 单例模式
  3. 单:单一
  4. 例:实例
  5. 一个构造函数一生只能有一个实例,不管你new多少次,都是这一个实例
  6. 应用:自定义弹出层
  7. 结构:div 》 xxxx, 默认隐藏,在一定条件下显示
  8. 实现:每次都是一个div来回显示,只是内容不一样
  9. */
  10. const Person = (function () {
  11. function Person(name, age) {
  12. this.name = name
  13. this.age = age
  14. }
  15. let instance = null
  16. return function singleTon(...args) {
  17. if (!instance) {
  18. instance = new Person(...args)
  19. }
  20. return instance
  21. }
  22. })()
  23. const p1 = new Person('Jack', 20)
  24. const p2 = new Person('Rose', 30)
  25. console.log(p1, p2)
  26. console.log(p1 === p2) // true

2. 观察者模式

  1. /*
  2. 观察者模式:
  3. + 例子:监控
  4. => 我们坐在教室里就是被观察者
  5. => 监控后面的老师就是观察者
  6. => 当被观察者触发了一些条件的时候,观察者就会触发技能
  7. + 观察者模式:监控一个对象的状态,一旦状态发生变化,马上触发技能
  8. => 需要两个构造函数来实现
  9. 1. 创建被观察者
  10. => 属性,自己的状态
  11. => 队列,记录都有谁观察自己
  12. => 方法1,能设置自己的状态,当我需要改变的时候,触发这个方法改变状态
  13. => 方法2,添加观察者
  14. => 方法3,删除观察者
  15. 2. 创建观察者
  16. => 需要一个身份证明
  17. => 需要一个技能
  18. */
  19. // 观察者构造函数
  20. class Observer {
  21. constructor(name, fn = () => {}) {
  22. this.name = name
  23. this.fn = fn
  24. }
  25. }
  26. // 创建三个个观察者
  27. const njzr = new Observer('年级主任', (state) => {
  28. console.log('因为:' + state + '所以:告诉你的班主任')
  29. })
  30. const bzr = new Observer('班主任', (state) => {
  31. console.log('因为:' + state + '所以:把你爸找来')
  32. })
  33. const xz = new Observer('校长', (state) => {
  34. console.log('因为:' + state + '所以:骂你的班主任')
  35. })
  36. // console.log(bzr, xz)
  37. // 被观察者构造函数
  38. class Subject {
  39. constructor(state) {
  40. this.state = state // 记录自己的状态
  41. this.observers = [] // 保存观察着我的人
  42. }
  43. // 设置自己的状态
  44. setState(state) {
  45. this.state = state
  46. // 就需要把我的所有观察者的技能都触发
  47. // 遍历this.observers 依次触发技能
  48. this.observers.forEach(item => {
  49. // 把每一个观察者的技能触发
  50. // 告诉他我改变成了什么状态
  51. item.fn(this.state)
  52. })
  53. }
  54. // 添加观察者
  55. addObserver(obs) {
  56. this.observers = this.observers.filter(item => item !== obs)
  57. this.observers.push(obs)
  58. }
  59. // 删除观察者
  60. delObserver(obs) {
  61. this.observers = this.observers.filter(item => item !== obs)
  62. }
  63. }
  64. // 创建一个被观察者
  65. const xiaoming = new Subject('学习')
  66. xiaoming.addObserver(njzr)
  67. xiaoming.addObserver(bzr)
  68. xiaoming.addObserver(xz)
  69. console.log(xiaoming)
  70. const xiaohong = new Subject('学习')
  71. xiaohong.addObserver(bzr)
  72. xiaohong.addObserver(xz)
  73. console.log(xiaohong)

3. 发布订阅模式

    /*
      发布订阅模式
        + 有一个对象,有人在一直看着他
        + 当这个对象发生改变的时候,第三方通知这个看着的人,触发技能
        + 例子:买书
          1. 普通程序员买书
            => 去书店,问,没有
            => 回家
            => 过一会儿再去,问,没有,回家
            => 过一会儿再去,问,没有,回家
          2. 发布订阅的程序员
            => 去书店买书,问,没有,留下一个联系方式给店员
            => 一旦有了书,就会接到电话
            => 触发技能去买书
        + 只需要一个构造函数
        => 创建一个第三方店员的身份
        => 我们的任务就是模拟一个addEventListener()

      分析构造函数
        + 属性:任务队列
          {
            click:[fn1, fn2]
            abc:[fn1, fn2, fn3]
          }
        + 方法1:能向消息队列里面添加内容
        + 方法2:删除队列里面的内容
        + 方法3:触发消息队列
    */

    // 第三方观察者类
    class Observer {
      constructor() {
        this.message = {}
      }

      // 1. 向消息队列里面添加内容
      on(type, fn) {
        // type: 我拜托你看着的行为
        // fn: 在行为发生后,你要做的事情
        // 把这些记录在消息队列中
        // 1. 判断行为是否被注册过
        if (!this.message[type]) {
          this.message[type] = []
        }

        this.message[type].push(fn)

      }
      // 2. 删除消息队列里面的内容
      off(type, fn) {
        // fn不存在,只有一个参数的情况
        if (!fn) {
          // 直接把这个事情取消掉
          delete this.message[type]
          return
        }

        // fn存在
        if (!this.message[type]) return // 没订阅过什么都不做

        // 订阅过
        this.message[type] = this.message[type].filter(item => item !== fn)

      }
      // 3. 触发消息队列
      trigger(type) {
        if (!this.message[type]) return // 判断是否被订阅过

        this.message[type].forEach(item => {
          item()
        })
      }
    }


    // 创建一个观察者实例
    const person1 = new Observer()
    console.log(person1)

    // 当你想拜托这个person1帮你观察一些内容的时候
    // 要告诉他一个行为,当行为出现的时候,告诉他该干什么(订阅一个行为)
    person1.on('高程3', handlerA)
    person1.on('高程3', handlerB)
    person1.on('犀牛书', handlerC)
    person1.on('犀牛书', handlerD)


    // 1. 我的朋友送给我了犀牛书,我的这个事情不用你管了(取消订阅)
    // person1.off('犀牛书')
    // 2. 犀牛书来了,只去办C,不用去办D了
    // person1.off('犀牛书', handlerD)

    // person1.off('你不知道的js', handlerE)


    // person一旦触发a行为,就要把后面所有的时间都进行处理
    person1.trigger('高程3')

    function handlerA() {
      console.log('handlerA')
    }

    function handlerB() {
      console.log('handlerB')
    }

    function handlerC() {
      console.log('handlerC')
    }

    function handlerD() {
      console.log('handlerD')
    }

4. 策略模式

    /*
        策略模式
          + 一个问题可以匹配多个解决方案,不一定要用到哪一个
          + 而且有可能随时还会继续添加多个方案
          + 例子:购物车结算
              => 我们有好多种折扣计算方式
              => 满 100 减 10
              => 满 200 减 25
              => 8折
        1. 把我们的多种方案,以闭包的形式保存起来
          + 按照传递进来的折扣和价格计算最终的价格返回
        2. 留下添加折扣方式和删除折扣方式的接口
          + 函数也是一个对象
          + 可以把函数名当做一个对象,向里面添加一些成员
    */


    // 接受两个参数,1. 价格  2. 折扣种类
    // 如果现在多了一种折扣方式,我们就需要改源代码,加一个else if判断
    // 活动结束后,还要删除这个方式
    // function calcPrice(price, type) {
    //   if (type === '100_10') {
    //     price -= 10
    //   } else if (type === '200_25') {
    //     price -= 25
    //   } else if (type === '80%') {
    //     price *= 0.8
    //   } else {
    //     console.log('没有这种折扣方式')
    //   }
    //   return price
    // }

    // const res = calcPrice(320, '100_10')
    // console.log(res)




    // 1. 暂时以闭包的形式把折扣方案保存下来

    const calcPrice = (function () {
      const sale = {
        '100_10': function (price) {
          return price -= 10
        },
        '200_25': function (price) {
          return price -= 25
        },
        '80%': function (price) {
          return price *= 0.8
        }
      }

      function calcPrice(price, type) {
        if (!sale[type]) return '没有这个折扣方案'
        return sale[type](price)
      }

      // 把函数当做一个对象,向里面添加一些成员
      calcPrice.add = function (type, fn) {
        // 判断折扣方式是否存在
        if (sale[type]) return '该折扣方式已经存在'
        sale[type] = fn
        return '添加成功'
      }

      // 删除成员
      calcPrice.del = function (type) {
        delete sale[type]
      }
      return calcPrice
    })()
    const res = calcPrice.add('100_50', price => price -= 50)
    // console.log(res)
    let result = calcPrice(320, '100_50')
    console.log(result)