浅谈设计模式之抽象工厂模式

抽象工厂模式(Abstract factory pattern)

抽象工厂模式(Abstract factory pattern)是一种软件开发设计模式。抽象工厂模式提供了一种方式,可以将一组具有同一主题的单独的工厂封装起来。在正常使用中,客户端程序需要创建抽象工厂的具体实现,然后使用抽象工厂作为接口来创建这一主题的具体对象。客户端程序不需要知道(或关心)它从这些内部的工厂方法中获得对象的具体类型,因为客户端程序仅使用这些对象的通用接口。抽象工厂模式将一组对象的实现细节与他们的一般使用分离开来。

定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。

类型:创建类模式

类图:
UML

GuiFactory接口中的createButton方法返回Button类型的对象。返回Button的哪种实现依赖于使用GuiFactory的哪种实现。

需要注意的是,为了简洁起见,以上类图仅仅展示了创建一个类型对象的工厂。而在抽象工厂模式中,通常一个工厂能够创建若干种不同类型的对象。


产品族

先来认识下什么是产品族:位于不同产品等级结构中,功能相关联的产品组成的家族。还是让我们换一个例子来形象地说明一下吧。

产品族

图中的BmwCarBenzCar就是两个产品树(产品层次结构);而如图所示的BenzSportsCarBmwSportsCar就是一个产品族。他们都可以放到跑车家族中,因此功能有所关联。同理BmwBussinessCarBenzSportsCar也是一个产品族。


回到抽象工厂模式的话题上。

可以说,抽象工厂模式和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。

抽象工厂模式的用意为:给客户端提供一个接口,可以创建多个产品族中的产品对象。

而且使用抽象工厂模式还要满足一下条件:

  1. 系统中有多个产品族,而系统一次只可能消费其中一族产品。

  2. 同属于同一个产品族的产品以其使用。

来看看抽象工厂模式的各个角色(和工厂方法的如出一辙):

  1. 抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

  2. 具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。

  3. 抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。

  4. 具体产品角色:具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。

类图如下:
抽象工厂模式


代码举例

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
// 产品 Plant接口
public interface Plant { }//标志接口
//具体产品PlantA,PlantB
public class PlantA implements Plant {
public PlantA () {
   System.out.println("create PlantA !");
  }
  public void doSomething() {
   System.out.println(" PlantA do something ...");
  }
}
public class PlantB implements Plant {
  public PlantB () {
   System.out.println("create PlantB !");
  }
  public void doSomething() {
   System.out.println(" PlantB do something ...");
  }
}
//产品Fruit接口
public interface Fruit { }
//具体产品FruitA,FruitB
public class FruitA implements Fruit {
  public FruitA() {
   System.out.println("create FruitA !");
  }
  public void doSomething() {
   System.out.println(" FruitA do something ...");
  }
}
public class FruitB implements Fruit {
  public FruitB() {
   System.out.println("create FruitB !");
  }
  public void doSomething() {
   System.out.println(" FruitB do something ...");
  }
}
//抽象工厂方法
public interface AbstractFactory {
  public Plant createPlant();
  public Fruit createFruit();
}
//具体工厂方法
public class FactoryA implements AbstractFactory {
  public Plant createPlant() {
   return new PlantA();
  }
  public Fruit createFruit() {
   return new FruitA();
  }
}
public class FactoryB implements AbstractFactory {
  public Plant createPlant() {
   return new PlantB();
  }
  public Fruit createFruit() {
   return new FruitB();
  }
}
1
2
3
4
5
6
7
//调用工厂方法
public class Client {
public void method1() {
AbstractFactory instance = new FactoryA();
instance.createPlant();
}
}

建议可以看看GoF的《设计模式》一书,里面说到工厂模式时举得例子浅显易懂。


工厂方法模式与抽象工厂模式的区别

可以这么说,工厂方法模式是一种极端情况的抽象工厂模式,而抽象工厂模式可以看成是工厂方法模式的一种推广。

  1. 其实工厂方法模式是用来创建一个产品的等级结构的,而抽象工厂模式是用来创建多个产品的等级结构的。工厂方法创建一般只有一个方法,创建一种产品。抽象工厂一般有多个方法,创建一系列产品。

  2. 工厂方法模式只有一个抽象产品类,而抽象工厂模式有多个。工厂方法模式的具体工厂类只能创建一个具体产品类的实例,而抽象工厂模式可以创建多个。

简而言之,
工厂方法模式:

  • 一个抽象产品类,可以派生出多个具体产品类。
  • 一个抽象工厂类,可以派生出多个具体工厂类。
  • 每个具体工厂类只能创建一个具体产品类的实例。

抽象工厂模式:

  • 多个抽象产品类,每个抽象产品类可以派生出多个具体产品类。
  • 一个抽象工厂类,可以派生出多个具体工厂类。
  • 每个具体工厂类可以创建多个具体产品类的实例。

适用性

在以下情况可以考虑使用抽象工厂模式:

  • 一个系统要独立于它的产品的创建、组合和表示时。
  • 一个系统要由多个产品系列中的一个来配置时。
  • 需要强调一系列相关的产品对象的设计以便进行联合使用时。
  • 提供一个产品类库,而只想显示它们的接口而不是实现时。

优点

  • 具体产品从客户代码中被分离出来。
  • 容易改变产品的系列。
  • 将一个系列的产品族统一到一起创建。

缺点

  • 在产品族中扩展新的产品是很困难的,它需要修改抽象工厂的接口

参考资料: