1. 意图(Intent)

当涉及到产品族的时候,就需要引入抽象工厂模式了。
一个经典的例子是造一台电脑。我们先不引入抽象工厂模式,看看怎么实现。
因为电脑是由许多的构件组成的,我们将 CPU 和主板进行抽象,然后 CPU 由 CPUFactory 生产,主板由 MainBoardFactory 生产,然后,我们再将 CPU 和主板搭配起来组合在一起,如下图:
image.png
这个时候的客户端调用是这样的:

  1. public class Client {
  2. public static void main(String[] args) {
  3. // 得到 Intel 的 CPU
  4. CPUFactory cpuFactory = new IntelCPUFactory();
  5. CPU cpu = intelCPUFactory.makeCPU();
  6. // 得到 AMD 的主板
  7. MainBoardFactory mainBoardFactory = new AmdMainBoardFactory();
  8. MainBoard mainBoard = mainBoardFactory.make();
  9. // 组装 CPU 和主板
  10. Computer computer = new Computer(cpu, mainBoard);
  11. }
  12. }

单独看 CPU 工厂和主板工厂,它们分别是前面我们说的工厂模式。这种方式也容易扩展,因为要给电脑加硬盘的话,只需要加一个 HardDiskFactory 和相应的实现即可,不需要修改现有的工厂。

但是,这种方式有一个问题,那就是如果 Intel 家产的 CPU 和 AMD 产的主板不能兼容使用,那么这代码就容易出错,因为客户端并不知道它们不兼容,也就会错误地出现随意组合。

下面就是我们要说的产品族的概念,它代表了组成某个产品的一系列附件的集合:
image.png
当涉及到这种产品族的问题的时候,就需要抽象工厂模式来支持了。我们不再定义 CPU 工厂、主板工厂、硬盘工厂、显示屏工厂等等,我们直接定义电脑工厂,每个电脑工厂负责生产所有的设备,这样能保证肯定不存在兼容问题。
image.png
这个时候,对于客户端来说,不再需要单独挑选 CPU厂商、主板厂商、硬盘厂商等,直接选择一家品牌工厂,品牌工厂会负责生产所有的东西,而且能保证肯定是兼容可用的。

  1. public class Client {
  2. public static void main(String[] args) {
  3. // 第一步就要选定一个“工厂”
  4. ComputerFactory cf = new AmdFactory();
  5. // 从这个大厂造 CPU
  6. CPU cpu = cf.makeCPU();
  7. // 从这个大厂造主板
  8. MainBoard board = cf.makeMainBoard();
  9. // 从这个大厂造硬盘
  10. HardDisk hardDisk = cf.makeHardDisk();
  11. // 将同一个厂子出来的 CPU、主板、硬盘组装在一起
  12. Computer result = new Computer(cpu, board, hardDisk);
  13. }
  14. }

当然,抽象工厂的问题也是显而易见的,比如我们要加个显示器,就需要修改所有的工厂,给所有的工厂都加上制造显示器的方法。这有点违反了对修改关闭,对扩展开放这个设计原则。

2. 类图(Class Diagram)

抽象工厂模式创建的是对象家族,也就是很多对象而不是一个对象,并且这些对象是相关的,也就是说必须一起创建出来。而工厂方法模式只是用于创建一个对象,这和抽象工厂模式有很大不同。

抽象工厂模式用到了工厂方法模式来创建单一对象,AbstractFactory 中的 createProductA() 和 createProductB() 方法都是让子类来实现,这两个方法单独来看就是在创建一个对象,这符合工厂方法模式的定义。

至于创建对象的家族这一概念是在 Client 体现,Client 要通过 AbstractFactory 同时调用两个方法来创建出两个对象,在这里这两个对象就有很大的相关性,Client 需要同时创建出这两个对象。

从高层次来看,抽象工厂使用了组合,即 Cilent 组合了 AbstractFactory,而工厂方法模式使用了继承
image.png
抽象工厂(Abstract Factory) - 图5

3. 实现(Implementation)

  1. public class Keybo {
  2. abstract void sayHi();
  3. }
  1. public class DellKeybo extends Keybo {
  2. void sayHi(){
  3. print("Hi DellKeybo");
  4. }
  5. }
  1. public class HpKeybo extends Keybo {
  2. void sayHi(){
  3. print("Hi HpKeybo");
  4. }
  5. }
  1. public class Mouse {
  2. abstract void sayHi();
  3. }
  1. public class DellMouse extends Mouse {
  2. void sayHi(){
  3. print("Hi DellMouse");
  4. }
  5. }
  1. public class HpMouse extends Mouse {
  2. void sayHi(){
  3. print("Hi HpMouse");
  4. }
  5. }
  1. public abstract class pcFactory {
  2. abstract Mouse createMouse();
  3. abstract Keybo createKeybo();
  4. }
  1. public class DellFactory extends pcFactory {
  2. Mouse createMouse() {
  3. return new DellMouse();
  4. }
  5. Keybo createKeybo() {
  6. return new DellKeybo();
  7. }
  8. }
  1. public class HpFactory extends pcFactory {
  2. Mouse createMouse() {
  3. return new HpMouse();
  4. }
  5. Keybo createKeybo() {
  6. return new HpKeybo();
  7. }
  8. }
  1. public class Client {
  2. public static void main(String[] args) {
  3. pcFactory abstractFactory = new HpFactory(); //由惠普工厂实例化
  4. Mouse Hpmouse = abstractFactory.createMouse(); //生产惠普鼠标
  5. Keybo Hpkeybo = abstractFactory.createKeybo(); //生产惠普键盘
  6. // do something with Hpmouse and Hpkeybo
  7. }
  8. }

4. 增加华硕工厂 [ 工厂 ]

假设现在的生产厂家多了一个华硕,我们需要添加华硕鼠标,华硕键盘 。
抽象工厂(Abstract Factory) - 图6
实现代码该如何修改呢 ?
添加华硕键盘

  1. public class AsusKeybo extends Keybo {
  2. void sayHi(){
  3. print("Hi AsusKeybo");
  4. }
  5. }

添加华硕鼠标

  1. public class AsusMouse extends Mouse {
  2. void sayHi(){
  3. print("Hi AsusMouse");
  4. }
  5. }

添加华硕工厂

  1. public class AsusFactory extends pcFactory {
  2. Mouse createMouse() {
  3. return new AsusMouse();
  4. }
  5. Keybo createKeybo() {
  6. return new AsusKeybo();
  7. }
  8. }

5. 增加耳机产品 [ 产品 ]

假设现在的生产厂家多了一个产品耳机,我们需要添加惠普耳机,戴尔耳机 。
抽象工厂(Abstract Factory) - 图7
实现代码该如何修改呢 ?

添加部分

添加耳机抽象类

  1. public class Mic {
  2. abstract void sayHi();
  3. }

添加惠普耳机

  1. public class HpMic extends Mic {
  2. void sayHi(){
  3. print("Hi HpMic");
  4. }
  5. }

添加戴尔耳机

  1. public class DellMic extends Mic {
  2. void sayHi(){
  3. print("Hi DellMic");
  4. }
  5. }

修改部分

修改抽象工厂类

  1. public abstract class pcFactory {
  2. abstract Mouse createMouse();
  3. abstract Keybo createKeybo();
  4. abstract Mic createMic(); //添加生产耳机抽象方法
  5. }

修改惠普工厂类

  1. public class HpFactory extends pcFactory {
  2. Mouse createMouse() {
  3. return new HpMouse();
  4. }
  5. Keybo createKeybo() {
  6. return new HpKeybo();
  7. }
  8. //实现生产惠普耳机抽象方法
  9. Mic createMic() {
  10. return new HpMic();
  11. }
  12. }

修改戴尔工厂类

  1. public class DellFactory extends pcFactory {
  2. Mouse createMouse() {
  3. return new HpMouse();
  4. }
  5. Keybo createKeybo() {
  6. return new HpKeybo();
  7. }
  8. //实现生产戴尔耳机抽象方法
  9. Mic createMic() {
  10. return new DellMic();
  11. }
  12. }

6. JDK