首页 > 技术文章 > 简单工厂函数

zaisanshuiyifang 2021-11-01 16:59 原文

前文提到过在实际开发中,不发生变化的代码可以说是不存在的。我们能做的只有将这个变化造成的影响最小化 —— 将变与不变分离,确保变化的部分灵活、不变的部分稳定。那么我们的设计模式的时候就是为了区分变和不变,本文通过一些例子去体验开发过程中随着需求变动,设计一个好的模式是多么重要。

简单讲一下构造器

在录入一个公司员工信息的时候,我们可以直接创建一个单独的对象来描述自己:

  const liLei = {
    name: '李雷',
    age: 25,
    career: 'coder',
}

当公司又来了个美女同时叫你录入系统的时候,你可以再加上一个对象

   const liLei = {
    name: '李雷',
    age: 25,
    career: 'coder',
  }
  const lilith= {
    name:'lilith',
    age:'23',
    career:'coder'
  }

问题来了,如果公司突然来了一千个人,那么每个都这么录入的话,估计会吃不消。
那么我们现在分析描述员工的对象中,什么是变的什么是不变的?
我们很容易就能知道,变的是姓名、年龄、工种这些值,每个员工的个性,不变的是每个员工都具备姓名、年龄、工种这些属性
那么我们是不是可以将 name、age、career 赋值给对象的过程封装,确保了每个对象都具备这些属性,确保了共性的不变,同时将 name、age、career 各自的取值操作开放,确保了个性的灵活。

  function User(name , age, career) {
      this.name = name
      this.age = age
      this.career = career 
  }
 const liLei  = new User('李雷', 25 , 'coder') 
 const lilith = new User('lilith', 23 , 'coder')
 ...

楼上个这 User,就是一个构造器。此处我们采用了 ES5 构造函数的写法,因为 ES6 中的 class 其实本质上还是函数,class 语法只是语法糖,构造函数,才是它的真面目。

简单工厂函数

如果在使用构造器模式的时候,我们本质上是去抽象了每个对象实例的变与不变。那么使用工厂模式时,我们要做的就是去抽象不同构造函数(类)之间的变与不变。
现在新的需求来了,公司来了一个测试,又来了个产品经理,又来了个后端开发,光一个职位是描述不清楚这个人具体是做什么的,那么老板要求加上一个work属性,你可能会这么去思考,每个职业创造一个类

function  frontEndCoder(name , age) {
    this.name = name
    this.age = age
    this.career = 'frontEndCoder' 
    this.work = ['切图仔','html', 'css']
}
function  backEndCoder(name , age) {
    this.name = name
    this.age = age
    this.career = 'backEndCoder' 
    this.work = ['mySQL','java', 'springboot']
}
function ProductManager(name, age) {
    this.name = name 
    this.age = age
    this.career = 'product manager'
    this.work = ['订会议室', '写PRD', '催更']
}
...

现在我们要输入这几个人的信息,那么我们可以从数据库拿到数据,然后手动调用每个类

  const liLei  = new User('李雷', 25 , 'backEndCoder') 
  const  lilith = new User('lilith', 23 , 'frontEndCoder') 
 ...

但是数据库有三十几个职业,那么每个都需要我们去手动创建,不行,这也是一个“变”,我们把这个“变”交给一个函数去处理:

  function Factory(name, age, career) {
    switch(career) {
        case 'frontEndCoder':
            return new Coder(name, age) 
            break
        case 'product manager':
            return new ProductManager(name, age)
            break
        ...
  }

咋一看我们这样写是没什么问题的,但是我们再想一想,如果公司有几十个不同的工种,那么我们就该哭了,我要去创建几十个不同的类,然后再通过switch去生成员工信息么?
我们再回头去想想,这些构造器中什么是变的,什么是不变的。变的是根据不同的职位work描述不同,不变的是name,age, career , work 这些属性值。

function User(name , age, career, work) {
    this.name = name
    this.age = age
    this.career = career 
    this.work = work
}

function Factory(name, age, career) {
    let work
    switch(career) {
        case 'forntEndcoder':
            work =  ['写代码','写系分', '修Bug'] 
            break
        case 'product manager':
            work = ['订会议室', '写PRD', '催更']
            break
        case 'boss':
            work = ['喝茶', '看报', '见客户']
        case 'xxx':
            // 其它工种的职责分配
            ...
            
    return new User(name, age, career, work)
}

现在我们一起来总结一下什么是工厂模式:工厂模式其实就是将创建对象的过程单独封装。它很像我们去餐馆点菜:比如说点一份西红柿炒蛋,我们不用关心西红柿怎么切、怎么打鸡蛋这些菜品制作过程中的问题,我们只关心摆上桌那道菜。在工厂模式里,我传参这个过程就是点菜,工厂函数里面运转的逻辑就相当于炒菜的厨师和上桌的服务员做掉的那部分工作——这部分工作我们同样不用关心,我们只要能拿到工厂交付给我们的实例结果就行了。

总结一下:工厂模式的目的,就是为了实现无脑传参,就是为了爽!

小结

工厂模式的简单之处,在于它的概念相对好理解:将创建对象的过程单独封装,这样的操作就是工厂模式。同时它的应用场景也非常容易识别:有构造函数的地方,我们就应该想到简单工厂;在写了大量构造函数、调用了大量的 new、自觉非常不爽的情况下,我们就应该思考是不是可以掏出工厂模式重构我们的代码了。

但工厂模式可不止这一种表达形式。本节我们可以看到,构造器解决的是多个对象实例的问题,简单工厂解决的是多个类的问题。那么当复杂度从多个类共存上升到多个工厂共存时又该怎么处理呢?在下个小节,我们一起来看看这个问题。
转载掘金小册《JavaScript 设计模式核⼼原理与应⽤实践》

推荐阅读