# 设计模式

# 工厂模式

  • 特点
    • 将new操作单独封装(new操作主要出现在面向对象创建实例的过程中)
    • 遇到new时,就该考虑是否要使用工厂模式
  • 示例
    • 你去购买汉堡,直接点餐取餐,不用自己做
    • 商店要’封装‘做汉堡的工作,做好直接给买者
  • 代码演示
    • 初始化一个产品类,再初始化一个工厂类,产品要给外部的人来用,但不直接暴露,而是通过工厂类将其暴露
class Product{
  constructor(name){
    this.name = name
  }
  init(){
    console.log('init')
  }
  fn1(){
    console.log('fn1')
  }
  fn2(){
    console.log('fn2')
  }
}
class Factor{
  create(name){
    return new Product(name)
  }
}
let factor = new Factor()
let product = factor.create('hahah')
product.init()
product.fn1()
  • 应用场景
    • jQuery中$('div'), jQuery库的封装实现基于工厂模式
    class jQuery{
      constructor(selector){}
      append(){}
      addClass(){}
      html(){}
    }
    Window.$ = function(selector){
      return new jQuery(selector)
    }
    
    • React.createElement
    class Vnode{
      constructor(tags, attrs, children){
        //省略内部实现代码 
      }
    }
    React.createElement = function(tags, attrs, children){
      return new Vnode(tags, attrs, children)
    }
    
    • vue异步组件
    Vue.component('example-component', ()=>{
      setTimeout(()=>{
        resolve({
          template: '<div>hello</div>'
        })
      }, 1000)
    })
    
  • 阅读经典lib源码的意义
    • 学习如何实现功能
    • 学习设计思路
    • 强制自己写代码,最后写出更好的代码
    • 先拿来主义,消化吸收后,再去创新
  • 设计原则验证
    • 构造函数与创建者分离,即产品与工厂分离
    • 符合开放封闭原则,即通过工厂方法将构造函数与用户隔离,使他们之间不产生耦合关系

# 单例模式

  • 特点
    • 系统中被唯一使用
    • 一个类只能初始化一个实例
  • 示例
    • 登录框
    • 购物车
  • 单例模式的实现思路
    • 如果有了,就直接用,如果没有,就实例化一个,但始终保证这个实例是系统中被唯一使用的
  • 代码演示
  • 利用Symbol实现node模块的单例模式
const FOO_KEY = Symbol.for('foo')
function A(){
  this.foo = 'hello'
}
if(!global[FOO_KEY]){
  global[FOO_KEY] = new A()
}

module.exports = global[FOO_KEY]
  • Singleton 模式指的是调用一个类,任何时候返回的都是同一个实例
class SingleObject{
  login(){
    console.log('login......')
  }
}
SingleObject.getInstance = (() => {
  let instance
  return function(){
    if(!instance){
      instance = new SingleObject()
    }
    return instance
  }
})()

// 注意:这里只能使用静态方法SingleObject.getInstance()生成单例,而不能使用new SingleObject()
let obj1 = SingleObject.getInstance()
obj1.login()
let obj2 = SingleObject.getInstance()
obj2.login()
console.log(obj1===obj2) //true  obj1与obj2是同一单例,完全相等
let obj3 = new SingleObject()
console.log(obj1===obj3) //false
  • 应用场景
    • jQuery中只有一个'$'
    if(window.jQuery!=null){
      return window.jQuery
    }else{
      //实例化一个
    }
    
    • 模拟登录框
    class loginForm{
      constructor(){
        this.state = 'hide'
      }
      show(){
        if(this.state === 'show'){
          console.log('已显示')
          return
        }
        this.state = 'show'
        console.log('登录框显示成功')
      }
      hide(){
        if(this.state === 'hide'){
          console.log('已隐藏')
          return
        }
        this.state = 'hide'
        console.log('登录框隐藏成功')
      }
    }
    loginForm.getInstance=(()=>{
      let instance
      return function(){
        if(!instance){
          instance = new loginForm()
        }
        return instance
      }
    })()
    
    let loginForm1 = loginForm.getInstance()
    loginForm1.show() //登录框显示成功
    let loginForm2 = loginForm.getInstance()
    loginForm2.show() //已显示,因为loginForm1与loginForm2是同一个登录框
    console.log(loginForm1===loginForm2)
    
    
    • 购物车
    • vuex和redux中的store
  • 设计原则验证
    • 符合单一指责原则,只实例化唯一的对象
    • 没法具体符合开放封闭原则,但绝对不违反开放封闭原则

# 观察者模式

  • 前端应用最多的一种设计模式
  • 特点:
    • 发布 & 订阅
    • 一对多,当然也可以一对一
  • 订阅某个主题,当主题发生变化时,通知所有的观察者去执行相应的操作
  • 代码演示·
// 保存状态,状态变化之后触发所有观察者对象
class Subject {
    constructor(){
      this.state = 0
      this.observers = []
    }
    getState(){
      return this.state
    }
    setState(state){
      this.state = state
      this.notifyAllObservers()
    }
    notifyAllObservers(){
      this.observers.forEach(observer => {
        observer.update()
      })
    }
    attach(observer){
      this.observers.push(observer)
    }
  }
  // 观察者
  class Observer {
    constructor(name, subject){
      this.name = name
      this.subject = subject
      this.subject.attach(this)
    }
    update(){
      console.log(`${this.name} updated, state: ${this.subject.getState()}`)
    }
  }
  
  // 测试
  let s = new Subject()
  let o1 = new Observer('o1', s)
  let o2 = new Observer('o2', s)
  
  s.setState(1)
  // o1 updated, state: 1
  // o2 updated, state: 1
  • 应用场景
    • 网页事件绑定,所有的事件监听机制
    • Promise, .then(() =>{})
    • jQuery callbacks
    var callbacks = $.Callbacks() //这是jQuery比较底层的一个api
    callbacks.add(function(info){ //注册监听回调
      console.log('fn1', info)
    })
    callbacks.add(function(info){
      console.log('fn2', info)
    })
    callbacks.fire('gogogo') //触发
    callbacks.fire('haahah')
    
    • nodejs 自定义事件
    • nodejs 处理http请求;多进程通信
    • Vue,React中生命周期函数触发(发布订阅)
    • vue的watch
  • 设计原则验证
    • 主题与观察者分离,不是主动触发而是被动监听,两者解耦
    • 符合开放封闭原则