JavaScript 设计模式 (二) 工厂方法模式 Factory method pattern

277 阅读3分钟

前言

第一篇是读书笔记,本篇开始的具体设计模式会参考维基百科对于二十三种著名GoF设计模式的解释

有理解不到位的,或者错误的地方欢迎在文章下方留言

定义

定义:一个用于创建对象的接口,但是让子类决定实例化哪个类。工厂方法允许一个类延迟实例化它使用的子类。

示例

在创建类时经常遇到需要创建类似的但不完全一样的实例,比如创建一个类表示键盘

class Keyboard {
  constructor(properties) {
    this.brand = properties.brand
  }
}

class MechanicalKeyboard extends Keyboard {
  constructor(properties) {
    super(properties)
  }
}

个人理解

首先 Factory method pattern(工厂方法模式) 不等于 Factory function(工厂函数);

Factory function(工厂函数)

  • Factory function(工厂函数)的作用是返回一个对象。它可能是创建类的替代方法。
  • 在 JavaScript 没有 class 的概念时,大家都是用函数去模拟 class,但是这只是对于工厂方法模式的应用,并不是工厂方法模式本身
  • 注:设计模式是可复用的解决方案,并不是具体应用

例如:


// 创建
const People = ({ // 姓名
  lastName, // 姓
  firstName // 名
}) => ({
  lastName,
  firstName
})
 
const createProgrammer = ({ // 程序员
  lastName, // 姓
  firstName // 名
  programmingLanguage // 编程语言
}) => ({
  ...People({ firstName, lastName }),
  programmingLanguage
})
 
const createDriver = ({ // 司机
  lastName, // 姓
  firstName // 名
  driverLicense // 驾驶证
}) => ({
  ...People({ firstName, lastName }),
  driverLicense
})

// 使用
const programmer = createProgrammer({
  firstName: '耿',
  lastName: '司机',
  programmingLanguage: 'JavaScript'
})
 
const driver = createDriver({
  firstName: '王',
  lastName: '大厨',
  driverLicense: 'A1'
})

Factory method pattern(工厂方法模式)

关于工厂方法模式的定义我找了几个关键词:

  • 创建对象的接口
  • 允许类延迟实例化它使用的子类

那我们可以把创建对象时用到的一些类看做网站数据库里的数据, 而工厂方法模式的实例就是后台给我们的一个数据接口,
我们传进去一些参数(要什么对象),后台返回一些数据(创建的对象),
而我们不需要知道这些数据到底怎么被查出来的(具体如何实现), 放在了哪里(具体如何定义),
而且在调用接口前并不需要去做查询操作(用到后才实例化)

流程图

工厂流程图.png

部分代码示例

ES6
class People {
  // 基础人模板
  name = "基础人模板";
  constructor(props) {
    this.name = props.name;
  }
}
class Programmer extends People {
  // 程序员
  programmingLanguage = "JavaScript";
  constructor(props) {
    super(props);
    this.programmingLanguage = props.programmingLanguage;
  }
}
class Driver extends People {
  // 司机
  driverLicense = "无证老司机";
  constructor(props) {
    super(props);
    this.driverLicense = props.driverLicense;
  }
}

class Chef extends People {
  // 厨师
  cookCard = "无证";
  constructor(props) {
    super(props);
    this.cookCard = props.cookCard;
  }
}


class PeopleFactory {
  public static createProgrammer(props) {
    return new Programmer(props);
  }
  public static createDriver(props) {
    return new Driver(props);
  }
  public static createChef(props) {
    return new Chef(props);
  }
}

const unlicensedDriver = PeopleFactory.createDriver({
  name: "老司机",
  driverLicense: "A1"
});
console.log(unlicensedDriver);
typescript
interface PeopleProps {
  // 基础人接口
  name: string;
}
interface ProgrammerProps extends PeopleProps {
  // 程序员接口
  programmingLanguage: string;
}
interface DriverProps extends PeopleProps {
  // 司机接口
  driverLicense: string;
}
interface ChefProps extends PeopleProps {
  // 厨师接口
  cookCard: string;
}

class People {
  // 基础人模板
  name: string = "基础人模板";
  constructor(props: PeopleProps) {
    this.name = props.name;
  }
}

class Programmer extends People {
  // 程序员
  programmingLanguage: string = "JavaScript";
  constructor(props: ProgrammerProps) {
    super(props);
    this.programmingLanguage = props.programmingLanguage;
  }
}
class Driver extends People {
  // 司机
  driverLicense: string = "无证老司机";
  constructor(props: DriverProps) {
    super(props);
    this.driverLicense = props.driverLicense;
  }
}

class Chef extends People {
  // 厨师
  cookCard: string = "无证";
  constructor(props: ChefProps) {
    super(props);
    this.cookCard = props.cookCard;
  }
}


class PeopleFactory {
  public static createProgrammer(
    props: ProgrammerProps
  ): Programmer {
    return new Programmer(props);
  }
  public static createDriver(
    props: DriverProps
  ): Driver {
    return new Driver(props);
  }
  public static createChef(props: ChefProps): Chef {
    return new Chef(props);
  }
}

const unlicensedDriver = PeopleFactory.createDriver({
  name: "老司机",
  driverLicense: "A1"
});
console.log(unlicensedDriver);

个人理解适用场景

  • 在团队中协作开发时,知道要创建很多相似不相同的类,但是暂时不知道所有的具体类是什么样子的,可以使用这个模式,等需要添加时直接在工厂类代码中添加静态方法,返回新的对象即可,这样可以方便代码的拓展与修改