# 简单工厂

下面我们新建了 Coder 和 Manager 两个构造函数,用于创建不同的员工,但是一个公司不可能只有两种工种,如果针对每种岗位都新建一个构造函数的话,未免过于繁琐。

function Coder(name, age, career) {
  this.name = name;
  this.age = age;
  this.career = career;
  this.work = '写代码';
}
function Manager(name, age, career) {
  this.name = name;
  this.age = age;
  this.career = career;
  this.work = '见客户';
}

从上面可以看出,两个构造函数都有 name、age、career、work 属性,只是 work 的值根据不同的工种有不同而已。 下面我们把相同的逻辑封装到 User 中

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

将不同的地方封装到 Factory 中

function Factory(name, age, career) {
  let work;
  switch(career) {
    case 'coder':
      work = '写代码';
      break;
    case 'manager':
      work = '见客户';
      break;
  }
  return new User(name, age, career);
}

这样我们在创建不同人员的时候只需要调用 Factory 方法就好了。

简单总结下:简单工厂模式是为了解决多个类的问题,将创建对象的过程单独封装。

# 抽象工厂

抽象工厂在前端的使用中并不多,只做了解即可。

class MobilePhoneFactory {
    // 提供操作系统的接口
    createOS(){
        throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
    }
    // 提供硬件的接口
    createHardWare(){
        throw new Error("抽象工厂方法不允许直接调用,你需要将我重写!");
    }
}
// 具体工厂继承自抽象工厂
class FakeStarFactory extends MobilePhoneFactory {
    createOS() {
        // 提供安卓系统实例
        return new AndroidOS()
    }
    createHardWare() {
        // 提供高通硬件实例
        return new QualcommHardWare()
    }
}

系统类:

// 定义操作系统这类产品的抽象产品类
class OS {
    controlHardWare() {
        throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
    }
}

// 定义具体操作系统的具体产品类
class AndroidOS extends OS {
    controlHardWare() {
        console.log('我会用安卓的方式去操作硬件')
    }
}

class AppleOS extends OS {
    controlHardWare() {
        console.log('我会用🍎的方式去操作硬件')
    }
}

硬件类:

// 定义手机硬件这类产品的抽象产品类
class HardWare {
    // 手机硬件的共性方法,这里提取了“根据命令运转”这个共性
    operateByOrder() {
        throw new Error('抽象产品方法不允许直接调用,你需要将我重写!');
    }
}

// 定义具体硬件的具体产品类
class QualcommHardWare extends HardWare {
    operateByOrder() {
        console.log('我会用高通的方式去运转')
    }
}

class MiWare extends HardWare {
    operateByOrder() {
        console.log('我会用小米的方式去运转')
    }
}

使用:

// 这是我的手机
const myPhone = new FakeStarFactory()
// 让它拥有操作系统
const myOS = myPhone.createOS()
// 让它拥有硬件
const myHardWare = myPhone.createHardWare()
// 启动操作系统(输出‘我会用安卓的方式去操作硬件’)
myOS.controlHardWare()
// 唤醒硬件(输出‘我会用高通的方式去运转’)
myHardWare.operateByOrder()

如需生产新的品牌手机,不需要对抽象工厂MobilePhoneFactory做任何修改,只需要拓展它的种类,这样不会对原有的系统不会造成任何潜在影响。

class newStarFactory extends MobilePhoneFactory {
    createOS() {
        // 操作系统实现代码
    }
    createHardWare() {
        // 硬件实现代码
    }
}

如果你使用过 TS, 有点像 TS 中的 interface。

  • 抽象工厂(抽象类,它不能被用于生成具体实例): 用于声明最终目标产品的共性。在一个系统里,抽象工厂可以有多个(大家可以想象我们的手机厂后来被一个更大的厂收购了,这个厂里除了手机抽象类,还有平板、游戏机抽象类等等),每一个抽象工厂对应的这一类的产品,被称为“产品族”。
  • 具体工厂(用于生成产品族里的一个具体的产品): 继承自抽象工厂、实现了抽象工厂里声明的那些方法,用于创建具体的产品的类。
  • 抽象产品(抽象类,它不能被用于生成具体实例): 上面我们看到,具体工厂里实现的接口,会依赖一些类,这些类对应到各种各样的具体的细粒度产品(比如操作系统、硬件等),这些具体产品类的共性各自抽离,便对应到了各自的抽象产品类。
  • 具体产品(用于生成产品族里的一个具体的产品所依赖的更细粒度的产品): 比如我们上文中具体的一种操作系统、或具体的一种硬件等。

抽象工厂模式的定义,是围绕一个超级工厂创建其他工厂。