抽象工厂模式

思考并回答以下问题:

  • 抽象工厂模式的官方定义是什么?
  • 抽象工厂比工厂模式有什么区别?

本章涵盖:

  • 抽象工厂模式的定义
  • 抽象工厂模式的实现
  • 可应用抽象工厂模式的场合

抽象工厂模式的定义

抽象工厂模式是工厂方法模式(Factory Method)的高级版,在介绍抽象工厂模式之前,让我们先来回顾工厂方法模式的定义与结构图。

工厂方法模式的定义

工厂方法模式(Factory Method)在GoF中的定义是:

1
定义一个可以产生对象的接口,但是让子类决定要产生哪一个类的对象。工厂方法模式让类的实例化程序延迟到子类中实行。

也就是,定义一个可以产生对象的接口,让子类决定要产生哪一个类的对象,其结构图如图1所示。

图1 工厂方法模式的结构图

抽象工厂模式的定义

抽象工厂模式(Abstract Factory)在GoF中的定义是:

1
提供一个能够建立整个类群组或有关联的对象,而不必指明它们的具体类。

抽象工厂模式的结构图如图2所示。

图2 抽象工厂模式的结构图

抽象工厂模式的应用方式是:系统中先定义一组抽象类(AbstractProductA、AbstractProductB),而这些抽象类的子类,是根据不同的执行环境去产生的,所以:

  • ProductA1和ProductB1是给执行环境1时使用的。
  • ProductA2和ProductB2是给执行环境2时使用的。

现在,系统如果要能根据当前的执行环境,自动决定要产生哪一组子类时,抽象工厂模式就可以派上用场。抽象工厂接口定义了产生不同类对象的方法(CreateProductA、CreateProductB),而继承的工厂子类,则是实现产生不同产品的类:

  • ConcreteFactory1是给执行环境1时使用的,可以产生ProductA1和ProductB1。
  • ConcreteFactory2是给执行环境2时使用的,可以产生ProductA2和ProductB2。

抽象工厂模式的实现

就上述结构图来说,以下是抽象工厂模式的范例程序:

Listing1 实现抽象工厂(AbstractFactory.cs)

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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// 可生成各抽象成品对象的操作
public abstract class AbstractFactory
{
public abstract AbstractProductA CreateProductA();
public abstract AbstractProductB CreateProductB();
}

// 实现可构建具体成品对象的操作1
public class ConcreateFactory1 : AbstractFactory
{
public ConcreateFactory1(){}

public override AbstractProductA CreateProductA()
{
return new ProductA1();
}
public override AbstractProductB CreateProductB()
{
return new ProductB1();
}
}

// 实现可构建具体成品对象的操作2
public class ConcreateFactory2 : AbstractFactory
{
public ConcreateFactory2(){}

public override AbstractProductA CreateProductA()
{
return new ProductA2();
}
public override AbstractProductB CreateProductB()
{
return new ProductB2();
}
}

// 成品对象类型A接口
public abstract class AbstractProductA
{
}

// 成品对象类型A1
public class ProductA1 : AbstractProductA
{
public ProductA1()
{
Debug.Log("生成对象类型A1");
}
}

// 成品对象类型A2
public class ProductA2 : AbstractProductA
{
public ProductA2()
{
Debug.Log("生成对象类型A2");
}
}

// 成品对象类型B接口
public abstract class AbstractProductB
{
}

// 成品对象类型B1
public class ProductB1 : AbstractProductB
{
public ProductB1()
{
Debug.Log("生成对象类型B1");
}
}

// 成品对象类型B2
public class ProductB2 : AbstractProductB
{
public ProductB2()
{
Debug.Log("生成对象类型B2");
}
}

测试程序如下:

Listing2 测试抽象工厂(AbstractFactoryTest.cs)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void UnitTest()
{
AbstractFactory Factory = null;

// 工厂1
Factory = new ConcreateFactory1();
// 产生两个产品
Factory.CreateProductA();
Factory.CreateProductB();

// 工厂2
Factory = new ConcreateFactory2();
// 产生两个产品
Factory.CreateProductA();
Factory.CreateProductB();
}

使用不同的子工厂类就可以产生对应的ProductA和ProductB:

执行结果

1
2
3
4
生成对象类型A1
生成对象类型B1
生成对象类型A2
生成对象类型B2

可应用抽象工厂模式的场合

Unity3D的界面设计-组合模式中,我们使用Unity3D内置的UI系统——UGUI用于开发玩家界面。而早在Unity3D发布UGUI系统之前,坊间就有不少Unity3D插件让游戏开发者使用如NGUI、iGUI等。在面对这么多样的工具可以选择之下,开发者最好能提供一个方便的架构让这些工具能快速转换使用。

设计上,我们可以先将每一个界面组件都设计为一个抽象类,如显示文字的ILabel、显示图片的IImage、提供选项的ICheckBox…,并在每个抽象类中定义共同的操作方法;然后针对每一个界面工具继承对应的子类,如针对NGUI工具的NGUILable、NGUImage…,针对iGUI定义的iGUILabel、iGUIImage等;最后,再针对不同群组的界面组件也实现出能产生它们的工厂,如能产生NGUI组件的NGUIFactory,能产生iGUI的iGUIFactory。

在这样的设计架构下,游戏开发者就能根据不同的需求来选择要使用的界面工具。虽然界面组件的设计摆放上需要使用对应工具,但是在程序设计上,只需要提供不同的界面工厂,就能将界面组件整个转换到不同的工具上。

当然,随着开发工具的演进,会有更多更新的界面开发工具出现。那时只要针对新的开发工具,继承实现新的界面组件及工厂类,就能马上让游戏快速转换到新的开发工具中。而这也是抽象工厂模式的优点:能将产生的对象“整组”转换到不同的类群组上。

0%