概念

抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一个接口用于创建相关或依赖对象的家族,而不需要指定具体类


抽象工厂模式通过引入抽象工厂接口和具体工厂实现类来实现这一点

在抽象工厂模式中,存在两个关键角色:抽象工厂(Abstract Factory)和具体工厂(Concrete Factory)

抽象工厂定义了创建产品家族的方法,而具体工厂实现了这些方法,用于创建具体的产品对象

每个产品家族都有一组相互关联的产品,而每个具体产品由具体工厂类创建

  1. 抽象工厂接口(Abstract Factory Interface)

    定义了一组创建产品的抽象方法,客户端通过调用这些抽象方法来创建产品

  2. 具体工厂类(Concrete Factory)

    实现了抽象工厂接口,负责创建一组相关的产品

  3. 抽象产品(Abstract Product)

    定义了一组产品的抽象接口或抽象类

  4. 具体产品(Concrete Product)

    实现了抽象产品接口或抽象类的具体类


抽象工厂模式的核心思想是通过引入抽象工厂来创建产品家族,使得客户端代码可以与具体的产品类解耦,从而使得系统更加灵活,能够更容易地应对需求变化


举个简单的例子,考虑一个跨平台图形界面工具包

可以有不同类型的界面元素(如按钮、文本框等),也可以有不同的主题(如浅色主题、深色主题等)

使用抽象工厂模式,可以将界面元素的类型和主题分离开来,使得可以很容易地添加新的界面元素类型或主题,而不需要修改已有的代码


实现条件

  1. 存在一组相关或相互依赖的产品

    抽象工厂模式适用于需要创建一组相关或相互依赖的产品的情况

    这些产品通常是属于同一产品族或产品等级结构的,它们之间有一定的关联性或依赖关系

  2. 需求频繁变化的系统

    如果系统中的产品族经常需要变化,或者需要支持多个不同的产品族,并且这些产品族的组成结构可能不断变化,那么抽象工厂模式可以提供一种灵活的方式来管理这些变化

  3. 客户端代码不依赖于具体产品类

    抽象工厂模式要求客户端代码不依赖于具体的产品类,而是通过抽象工厂接口来创建产品,从而实现了客户端代码与具体产品类的解耦

  4. 需要一致性的创建过程

    如果系统中的产品需要遵循一致的创建过程,并且这些产品的创建过程可能随着产品族的变化而变化,那么抽象工厂模式可以提供一种统一的方式来管理这些创建过程

  5. 需求层次结构化

    抽象工厂模式适用于系统中的产品具有层次结构的情况

    例如,产品族之间可能存在一定的层次结构关系,或者产品族内部的产品也可能具有层次结构


优点

  • 隔离具体类的生成

    使用者不需要知道具体的实现细节,只需关心接口和返回的抽象产品

  • 易于交换产品系列

    由于具体的工厂类在一个应用中只需要在初始化的时候出现一次,这使得改变一个应用的具体实现变得相对容易

  • 促进一致性

    当产品构成一系列的时候,确保客户端始终只使用同一个产品系列中的对象


缺点

  • 难以支持新种类的产品

    扩展抽象工厂以生产新种类的产品是困难的,这是因为接口确定后不容易修改


实现方式

使用ES6的Class创建最基础的抽象工厂接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* GenericAbstractFactoryPattern 是一个通用的抽象工厂模式类。
* 该类定义了创建不同类型汽车及其组件的方法,但并不具体实现这些方法。
* 子类需要根据具体的汽车类型实现这些抽象方法。
*/
class GenericAbstractFactoryPattern {
/**
* 创建汽车的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createCar () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建发动机的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createEngine () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建车架的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createChassis () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建车身的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createBody () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建电气系统的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createElectrical () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建变速器的方法。这是一个抽象方法,需要在子类中实现。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createTransmission () {
throw new Error('不能调用抽象方法,请自己实现')
}

/**
* 创建汽车类型的抽象方法。子类需要根据具体的汽车类型实现该方法。
* @throws {Error} 抛出错误提示不能调用抽象方法,请子类自己实现。
*/
createType () {
throw new Error('不能调用抽象方法,请自己实现')
}
}

export default GenericAbstractFactoryPattern

新建汽车基础类,让车辆继承父类的一些基本方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
export class Car {
constructor(options = {}) {
Object.assign(this, options || {})
}

drive() {
console.log('the name of the car that s driving right now is' + this.name)
}

stopDriving () {
console.log('the name of the car that stopped' + this.name)
}
}

export class Chassis {
constructor(options = {}) {
Object.assign(this, options || {})
}

assemble() {
console.log(`The chassis made of ${this.material} and type ${this.type} is being assembled.`);
}
}

export class Engine {
constructor(options = {}) {
Object.assign(this, options || {})
}

start() {
console.log(`The ${this.type} engine with ${this.horsepower} horsepower is starting.`);
}
}

新建子类进行调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import GenericAbstractFactoryPattern from '../AbstractFactoryPattern'
import { Car, Chassis, Engine } from './BasicCarClass'

/**
* AudiCar类,继承自Car类,代表一辆奥迪汽车。
* 该类通过构造函数初始化一辆奥迪汽车的具体属性。
*/
class AudiCar extends Car {
constructor(options) {
super({ name: 'Audi', lights: 'LED', color: 'Black', ...options })
}
}

class AudiEngine extends Engine {
constructor(options) {
super({ type: 'Audi Engine', horsepower: '300', ...options })
}
}

class AudiChassis extends Chassis {
constructor(options) {
super({ material: 'Aluminum', type: 'Audi Chassis', ...options })
}
}

/**
* AudiSubclass类,继承自GenericAbstractFactoryPattern类。
* 该类作为一个工厂类,用于创建奥迪品牌的汽车、发动机和车架。
*/
class AudiSubclass extends GenericAbstractFactoryPattern {
constructor(options) {
super()
this.options = options
}
/**
* 创建一辆奥迪汽车。
* @returns {AudiCar} 返回一个AudiCar实例。
*/
createCar () {
if (this.options && this.options.carInfo) {
return new AudiCar(this.options.carInfo)// 创建并返回一辆奥迪汽车实例
} else {
throw new Error('未提供正确的汽车信息')
}
}

/**
* 创建一个奥迪发动机。
* @returns {AudiEngine} 返回一个AudiEngine实例。
*/
createEngine () {
return new AudiEngine() // 创建并返回一个奥迪发动机实例
}

/**
* 创建一个奥迪车架。
* @returns {AudiChassis} 返回一个AudiChassis实例。
*/
createChassis () {
return new AudiChassis() // 创建并返回一个奥迪车架实例
}

}

export default AudiSubclass

然后在代码里面使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import AudiSubclass from './AudiSubclass'

const options = {
carInfo: {
name: 'Audi A4',
lights: 'LED',
color: 'Black'
}
}

// 创建AudiSubclass实例
const audiFactory = new AudiSubclass(options)

try {
// 使用工厂创建一个AudiCar实例
const myAudiCar = audiFactory.createCar()
// 调用drive方法
myAudiCar.drive()
} catch (error) {
console.error(error.message)
}


代码示例是一个抽象工厂模式的实现,它定义了创建汽车及其组件的通用接口。这个模式用于创建一系列相关或依赖对象的家族,而无需指定其具体类

  1. 抽象工厂类(GenericAbstractFactoryPattern

    这个类定义了一系列创建不同汽车组件的抽象方法,这是抽象工厂模式的典型实现,它允许子类来具体实现这些方法

  2. 具体工厂类(AudiSubclass

    这个类继承自抽象工厂类,并实现了创建奥迪汽车和相关组件的具体方法

    这里您只展示了createCar方法的实现,其他组件的创建方法(如createEnginecreateChassis)还没有具体的实现细节

  3. 具体产品类(AudiCar

    这是一个具体的产品类,它继承自Car类,并在构造函数中初始化了奥迪汽车的属性

  4. Car

    这个类定义了汽车的基础属性和方法,如drivestopDriving


场景

抽象工厂模式适用于以下情况:

  1. 系统要求产品族内的对象之间存在相互关联或依赖关系
  2. 系统需要独立于其产品的创建、组合和表示时


源代码