丁鹿学堂:前端设计模式之工厂模式详解

74 阅读2分钟

一个例子搞懂设计模式之工厂模式

需求:弹窗需求,弹窗类型有多种,有不同的样式和内容。
比如有三个构造函数分别是消息弹窗,确认弹窗和取消弹窗的

function infoPop(){}
function confirmPop(){}
function cancelPop(){}

常规做法,根据不同的需求,创建不同的实例

// 创建2个消息弹窗,2个确认弹窗,2个取消弹窗
// 常规做法
new infoPop('welcome','red')
new infoPop('hello','blue')
new confirmPop('success','green')

采用工厂模式:

  function pop(type,content,style){
    switch(type){
      case 'infoPop':
        return new infoPop(content,style)
      case 'confirmPop':
        return new confirmPop(content,style)
      case 'cancelPop':
        return new cancelPop(content,style)
    }
  }

分析: 不够健壮,如果用户不是直接调用pop,而是通过new 的方法调用pop,就会出现问题。

1我们先判断用户是否是new调用的,做相应的处理。 如果是new调用的,那么this 的instanceof是pop,我们就手动new 调用对应的构造函数。
如果不是通过new调用的,我们转为new调用该函数。

2不需要switch-case去判断,而是挂载到原型上去。这样以后如果添加方法,直接在原型上添加即可,不需要再去维护判断语句

3 把pop函数挂载到window上去 优化后的代码:

(function(){
  function pop(type,content,style){
    pop.prototype.infoPop = function(content,style){
      console.log(`infoPop-${content}:${style}`)
    }
    pop.prototype.confirmPop = function(content,style){
      console.log(`confirmPop-${content}:${style}`)
    }
    pop.prototype.cancelPop = function(content,style){
      console.log(`cancelPop-${content}:${style}`)
    }
    if(this instanceof pop){
      return new this[type](content,style)
    }else{
      return new pop(type,content,style)
    }
  }
  window.pop = pop
})()

这样,外部只需要调用我的工厂函数即可,而不用关心我要具体用哪个构造函数去new实例化一个对象。

let pops = [
  {type:'infoPop',content:'hello',style:'red'},
  {type:'infoPop',content:'welcome',style:'green'},
  {type:'cancelPop',content:'取消',style:'yellow'},
  {type:'cancelPop',content:'确定取消',style:'blue'},
  {type:'confirmPop',content:'确定?',style:'green'},
  {type:'confirmPop',content:'ok',style:'green'},
]

pops.forEach(item=>{
  let {type,content,style} = item
  pop(type,content,style)
})