创建型-抽象工厂(Abstract Factory)

3/13/2022 设计模式

摘要

JDK:1.8.0_202

# 一:场景问题

# 1.1 组装电脑

举个生活中常见的例子——组装电脑,我们在组装电脑的时候,通常需要选择一系列的配件,比如:CPU、硬盘、内存、主板、电源、机箱等等。为了使讨论简单点,只考虑选择CPU和主板的问题。

事实上,我们在选择CPU的时候,面临一系列的问题,比如:品牌、型号、针脚数目、主频等问题,只有把这些都确定下来,才能确定具体的CPU。同样,在选择主板的时候,也有一系列的问题,比如:品牌、芯片组、集成芯片、总线频率等问题,也只有这些都确定了,才能确定具体的主板。

选择不同的CPU和主板,是每个客户去组装电脑的时候,向装机公司提出的要求,也就是我们每个人自己拟定的装机方案。

在最终确定这个装机方案之前,还需要整体考虑各个配件之间的兼容性,比如:CPU和主板,如果CPU针脚数和主板提供的CPU插口不兼容,是无法组装的。也就是说,装机方案是有整体性的,里面选择的各个配件之间是有关联的

对于装机工程师而言,他只知道组装一台电脑,需要相应的配件,但是具体使用什么样的配件,还得由客户说了算。也就是说装机工程师只是负责组装,而客户负责选择装配所需要的具体的配件。因此,当装机工程师为不同的客户组装电脑时,只需要按照客户的装机方案,去获取相应的配件,然后组装即可。

现在需要使用程序来把这个装机的过程,尤其是选择组装电脑配件的过程实现出来,该如何实现呢?

# 1.2 不用模式的解决方案

考虑客户的功能,需要选择自己需要的CPU和主板,然后告诉装机工程师自己的选择,接下来就等着装机工程师组装机器了。

对装机工程师而言,只是知道CPU和主板的接口,而不知道具体实现,很明显可以用上简单工厂或工厂方法模式,为了简单,这里选用简单工厂吧。客户告诉装机工程师自己的选择,然后装机工程师会通过相应的工厂去获取相应的实例对象

接口:(CPUApi.java 和 MainboardApi.java)

/**
 * CPU的接口
 */
public interface CPUApi {

    /**
     * 示意方法,CPU具有运算的功能
     */
    void calculate();
}
1
2
3
4
5
6
7
8
9
10
/**
 * 主板的接口
 */
public interface MainboardApi {

    /**
     * 安装CPU
     */
    void installCPU();
}
1
2
3
4
5
6
7
8
9
10

CPU实现类:(IntelCPU.java 和 AMDCPU.java)

/**
 * Intel的CPU实现
 */
public class IntelCPU implements CPUApi {

    /**
     * CPU的针脚数目
     */
    private int pins;

    /**
     * 构造方法,传入CPU的针脚数目
     *
     * @param pins pins CPU针脚数目
     */
    public IntelCPU(int pins) {
        this.pins = pins;
    }

    @Override
    public void calculate() {
        System.out.println("now in Intel CPU,pins=" + pins);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * AMD的CPU实现
 */
public class AMDCPU implements CPUApi {

    /**
     * CPU的针脚数目
     */
    private int pins;

    /**
     * 构造方法,传入CPU的针脚数目
     *
     * @param pins CPU的针脚数目
     */
    public AMDCPU(int pins) {
        this.pins = pins;
    }

    public void calculate() {
        System.out.println("now in AMD CPU,pins=" + pins);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

主板实现类:(GAMainboard.java 和 MSIMainboard.java)

/**
 * 技嘉的主板
 */
public class GAMainboard implements MainboardApi {

    /**
     * CPU插槽的孔数
     */
    private int cpuHoles;

    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles CPU插槽的孔数
     */
    public GAMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    public void installCPU() {
        System.out.println("now in GAMainboard,cpuHoles=" + cpuHoles);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 微星的主板
 */
public class MSIMainboard implements MainboardApi {

    /**
     * CPU插槽的孔数
     */
    private int cpuHoles;

    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles CPU插槽的孔数
     */
    public MSIMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    public void installCPU() {
        System.out.println("now in MSIMainboard,cpuHoles=" + cpuHoles);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

工厂:(CPUFactory.java 和 MainboardFactory.java)

/**
 * 创建CPU的简单工厂
 */
public class CPUFactory {

    /**
     * 创建CPU接口对象的方法
     *
     * @param type 选择CPU类型的参数
     * @return CPU接口对象的方法
     */
    public static CPUApi createCPUApi(int type) {
        CPUApi cpu = null;
        //根据参数来选择并创建相应的CPU对象
        if (type == 1) {
            cpu = new IntelCPU(1156);
        } else if (type == 2) {
            cpu = new AMDCPU(939);
        }
        return cpu;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
 * 创建主板的简单工厂
 */
public class MainboardFactory {

    /**
     * 创建主板接口对象的方法
     *
     * @param type 选择主板类型的参数
     * @return 主板接口对象的方法
     */
    public static MainboardApi createMainboardApi(int type) {
        MainboardApi mainboard = null;
        //根据参数来选择并创建相应的主板对象
        if (type == 1) {
            mainboard = new GAMainboard(1156);
        } else if (type == 2) {
            mainboard = new MSIMainboard(939);
        }
        return mainboard;
    }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

装机工程师的实现:(ComputerEngineer.java)

/**
 * 装机工程师的类
 */
public class ComputerEngineer {

    /**
     * 定义组装机器需要的CPU
     */
    private CPUApi cpu = null;

    /**
     * 定义组装机器需要的主板
     */
    private MainboardApi mainboard = null;

    /**
     * 装机过程
     *
     * @param cpuType       客户选择所需CPU的类型
     * @param mainboardType 客户选择所需主板的类型
     */
    public void makeComputer(int cpuType, int mainboardType) {
        //1:首先准备好装机所需要的配件
        prepareHardwares(cpuType, mainboardType);
        //2:组装机器
        //3:测试机器
        //4:交付客户
    }

    /**
     * 准备装机所需要的配件
     *
     * @param cpuType       客户选择所需CPU的类型
     * @param mainboardType 客户选择所需主板的类型
     */
    private void prepareHardwares(int cpuType, int mainboardType) {
        //这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个
        //可是,装机工程师并不知道如何去创建,怎么办呢?

        //直接找相应的工厂获取
        this.cpu = CPUFactory.createCPUApi(cpuType);
        this.mainboard = MainboardFactory.createMainboardApi(mainboardType);
        //测试一下配件是否好用
        this.cpu.calculate();
        this.mainboard.installCPU();
    }

}
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

客户端实现:(Client1.java)

public class Client1 {

    public static void main(String[] args) {
        //创建装机工程师对象
        ComputerEngineer engineer = new ComputerEngineer();
        //告诉装机工程师自己选择的配件,让装机工程师组装电脑
        engineer.makeComputer(1, 1);
    }

}
1
2
3
4
5
6
7
8
9
10

# 1.3 有何问题

虽然上面的实现,通过简单工厂解决解决了:对于装机工程师,只知CPU和主板的接口,而不知道具体实现的问题。但还有一个问题没有解决,什么问题呢?那就是这些CPU对象和主板对象其实是有关系的,是需要相互匹配的。而在上面的实现中,并没有维护这种关联关系,CPU和主板是由客户随意选择的。这是有问题的。

这就是没有维护配件之间的关系造成的。该怎么解决这个问题呢?

# 二:解决方案

用来解决上述问题的一个合理的解决方案就是抽象工厂模式

抽象工厂:提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类

# 2.1 解决思路

仔细分析上面的问题,其实有两个问题点,一个是只知道所需要的一系列对象的接口,而不知具体实现,或者是不知道具体使用哪一个实现;另外一个是这一系列对象是相关或者相互依赖的。也就是说既要创建接口的对象,还要约束它们之间的关系。

有朋友可能会想,工厂方法模式或者是简单工厂,不就可以解决只知接口而不知实现的问题吗?怎么这些问题又冒出来了呢?

请注意,这里要解决的问题和工厂方法模式或简单工厂解决的问题是有很大不同的,工厂方法模式或简单工厂关注的是单个产品对象的创建,比如创建CPU的工厂方法,它就只关心如何创建CPU的对象,而创建主板的工厂方法,就只关心如何创建主板对象。

这里要解决的问题是,要创建一系列的产品对象,而且这一系列对象是构建新的对象所需要的组成部分,也就是这一系列被创建的对象相互之间是有约束的。

解决这个问题的一个解决方案就是抽象工厂模式。在这个模式里面,会定义一个抽象工厂,在里面虚拟的创建客户端需要的这一系列对象,所谓虚拟的就是定义创建这些对象的抽象方法,并不去真的实现,然后由具体的抽象工厂的子类来提供这一系列对象的创建。这样一来可以为同一个抽象工厂提供很多不同的实现,那么创建的这一系列对象也就不一样了,也就是说,抽象工厂在这里起到一个约束的作用,并提供所有子类的一个统一外观,来让客户端使用

# 2.2 模式结构和说明

抽象工厂模式结构如图所示:

结构图

  • AbstractFactory:抽象工厂,定义创建一系列产品对象的操作接口
  • ConcreteFactory:具体的工厂,实现抽象工厂定义的方法,具体实现一系列产品对象的创建
  • AbstractProduct:定义一类产品对象的接口
  • ConcreteProduct:具体的产品实现对象,通常在具体工厂里面,会选择具体的产品实现对象,来创建符合抽象工厂定义的方法返回的产品类型的对象
  • Client:客户端,主要使用抽象工厂来获取一系列所需要的产品对象,然后面向这些产品对象的接口编程,以实现需要的功能

# 2.3 示例代码

产品定义:(AbstractProductA.java 和 AbstractProductB.java)

/**
 * 抽象产品A的接口
 */
public interface AbstractProductA {
    //定义抽象产品A相关的操作
}
1
2
3
4
5
6
/**
 * 抽象产品B的接口
 */
public interface AbstractProductB {
    //定义抽象产品B相关的操作
}
1
2
3
4
5
6

抽象工厂定义:(AbstractFactory.java)

/**
 * 抽象工厂的接口,声明创建抽象产品对象的操作
 */
public interface AbstractFactory {
    /**
     * 示例方法,创建抽象产品A的对象
     *
     * @return 抽象产品A的对象
     */
    AbstractProductA createProductA();

    /**
     * 示例方法,创建抽象产品B的对象
     *
     * @return 抽象产品B的对象
     */
    AbstractProductB createProductB();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

A产品实现:(ProductA1.java 和 ProductA2.java)

/**
 * 产品A的具体实现
 */
public class ProductA1 implements AbstractProductA {
    //实现产品A的接口中定义的操作
}
1
2
3
4
5
6
/**
 * 产品A的具体实现
 */
public class ProductA2 implements AbstractProductA {
    //实现产品A的接口中定义的操作
}
1
2
3
4
5
6

B产品实现:(ProductB1.java 和 ProductB2.java)

/**
 * 产品B的具体实现
 */
public class ProductB1 implements AbstractProductB {
    //实现产品B的接口中定义的操作
}
1
2
3
4
5
6
/**
 * 产品B的具体实现
 */
public class ProductB2 implements AbstractProductB {
    //实现产品B的接口中定义的操作
}
1
2
3
4
5
6

工厂实现:(ConcreteFactory1.java 和 ConcreteFactory2.java)

/**
 * 具体的工厂实现对象,实现创建具体的产品对象的操作
 */
public class ConcreteFactory1 implements AbstractFactory {
    public AbstractProductA createProductA() {
        return new ProductA1();
    }

    public AbstractProductB createProductB() {
        return new ProductB1();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
/**
 * 具体的工厂实现对象,实现创建具体的产品对象的操作
 */
public class ConcreteFactory2 implements AbstractFactory {
    public AbstractProductA createProductA() {
        return new ProductA2();
    }

    public AbstractProductB createProductB() {
        return new ProductB2();
    }
}
1
2
3
4
5
6
7
8
9
10
11

客户端:(Client2.java)

public class Client2 {
    public static void main(String[] args) {
        // 创建抽象工厂对象
        AbstractFactory af = new ConcreteFactory1();
        // 通过抽象工厂来获取一系列的对象,如产品A和产品B
        af.createProductA();
        af.createProductB();
    }
}
1
2
3
4
5
6
7
8
9

# 2.4 重写案例

要使用抽象工厂模式来重写示例,先来看看如何使用抽象工厂模式来解决前面提出的问题。

装机工程师要组装电脑对象,需要一系列的产品对象,比如CPU、主板等,于是创建一个抽象工厂给装机工程师使用,在这个抽象工厂里面定义抽象的创建CPU和主板的方法,这个抽象工厂就相当于一个抽象的装机方案,在这个装机方案里面,各个配件是能够相互匹配的

每个装机的客户,会提出他们自己的具体装机方案,或者是选择已有的装机方案,相当于为抽象工厂提供了具体的子类,在这些具体的装机方案类里面,会创建具体的CPU和主板实现对象。

此时系统的结构如图所示:

结构图

接口:(CPUApi.java 和 MainboardApi.java)

/**
 * CPU的接口
 */
public interface CPUApi {

    /**
     * 示意方法,CPU具有运算的功能
     */
    void calculate();
}
1
2
3
4
5
6
7
8
9
10
/**
 * 主板的接口
 */
public interface MainboardApi {

    /**
     * 安装CPU
     */
    void installCPU();
}
1
2
3
4
5
6
7
8
9
10

CPU实现类:(IntelCPU.java 和 AMDCPU.java)

/**
 * Intel的CPU实现
 */
public class IntelCPU implements CPUApi {

    /**
     * CPU的针脚数目
     */
    private int pins;

    /**
     * 构造方法,传入CPU的针脚数目
     *
     * @param pins pins CPU针脚数目
     */
    public IntelCPU(int pins) {
        this.pins = pins;
    }

    @Override
    public void calculate() {
        System.out.println("now in Intel CPU,pins=" + pins);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * AMD的CPU实现
 */
public class AMDCPU implements CPUApi {

    /**
     * CPU的针脚数目
     */
    private int pins;

    /**
     * 构造方法,传入CPU的针脚数目
     *
     * @param pins CPU的针脚数目
     */
    public AMDCPU(int pins) {
        this.pins = pins;
    }

    public void calculate() {
        System.out.println("now in AMD CPU,pins=" + pins);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

主板实现类:(GAMainboard.java 和 MSIMainboard.java)

/**
 * 技嘉的主板
 */
public class GAMainboard implements MainboardApi {

    /**
     * CPU插槽的孔数
     */
    private int cpuHoles;

    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles CPU插槽的孔数
     */
    public GAMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    public void installCPU() {
        System.out.println("now in GAMainboard,cpuHoles=" + cpuHoles);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
 * 微星的主板
 */
public class MSIMainboard implements MainboardApi {

    /**
     * CPU插槽的孔数
     */
    private int cpuHoles;

    /**
     * 构造方法,传入CPU插槽的孔数
     *
     * @param cpuHoles CPU插槽的孔数
     */
    public MSIMainboard(int cpuHoles) {
        this.cpuHoles = cpuHoles;
    }

    public void installCPU() {
        System.out.println("now in MSIMainboard,cpuHoles=" + cpuHoles);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

抽象工厂:(AbstractFactory.java)

/**
 * 抽象工厂的接口,声明创建抽象产品对象的操作
 */
public interface AbstractFactory {
    /**
     * 创建CPU的对象
     *
     * @return CPU的对象
     */
    CPUApi createCPUApi();

    /**
     * 创建主板的对象
     *
     * @return 主板的对象
     */
    MainboardApi createMainboardApi();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

抽象工厂的实现对象:(Schema1.java 和 Schema2.java)

/**
 * 装机方案一:Intel 的CPU + 技嘉的主板
 * 这里创建CPU和主板对象的时候,是对应的,能匹配上的
 */
public class Schema1 implements AbstractFactory {
    public CPUApi createCPUApi() {
        return new IntelCPU(1156);
    }

    public MainboardApi createMainboardApi() {
        return new GAMainboard(1156);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
/**
 * 装机方案二:AMD的CPU + 微星的主板
 * 这里创建CPU和主板对象的时候,是对应的,能匹配上的
 */
public class Schema2 implements AbstractFactory {
    public CPUApi createCPUApi() {
        return new AMDCPU(939);
    }

    public MainboardApi createMainboardApi() {
        return new MSIMainboard(939);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

装机工程师的实现:(ComputerEngineer.java)

装机工程师类跟前面的实现相比,主要的变化是:从客户端,不再传入选择CPU和主板的参数,而是直接传入客户选择并创建好的装机方案对象。这样就避免了单独去选择CPU和主板,客户要选就是一套,就是一个系列。示例代码如下:

/**
 * 装机工程师的类
 */
public class ComputerEngineer {
    /**
     * 定义组装机器需要的CPU
     */
    private CPUApi cpu;
    /**
     * 定义组装机器需要的主板
     */
    private MainboardApi mainboard;

    /**
     * 装机过程
     *
     * @param schema 客户选择的装机方案
     */
    public void makeComputer(AbstractFactory schema) {
        //1:首先准备好装机所需要的配件
        prepareHardwares(schema);
        //2:组装机器
        //3:测试机器
        //4:交付客户
    }

    /**
     * 准备装机所需要的配件
     *
     * @param schema 客户选择的装机方案
     */
    private void prepareHardwares(AbstractFactory schema) {
        //这里要去准备CPU和主板的具体实现,为了示例简单,这里只准备这两个
        //可是,装机工程师并不知道如何去创建,怎么办呢?

        //使用抽象工厂来获取相应的接口对象
        this.cpu = schema.createCPUApi();
        this.mainboard = schema.createMainboardApi();

        //测试一下配件是否好用
        this.cpu.calculate();
        this.mainboard.installCPU();
    }
}
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

客户端:(Client2.java)

public class Client2 {
    public static void main(String[] args) {
        //创建装机工程师对象
        ComputerEngineer engineer = new ComputerEngineer();
        //客户选择并创建需要使用的装机方案对象
        AbstractFactory schema = new Schema1();
        //告诉装机工程师自己选择的装机方案,让装机工程师组装电脑
        engineer.makeComputer(schema);
    }
}
1
2
3
4
5
6
7
8
9
10

如同前面的示例,定义了一个抽象工厂AbstractFactory,在里面定义了创建CPU和主板对象的接口的方法,但是在抽象工厂里面,并没有指定具体的CPU和主板的实现,也就是无须指定它们具体的实现类。

CPU和主板是相关的对象,是构建电脑的一系列相关配件,这个抽象工厂就相当于一个装机方案,客户选择装机方案的时候,一选就是一套,CPU和主板是确定好的,不让客户分开选择,这就避免了出现不匹配的错误。

# 三:模式讲解

# 3.1 认识抽象工厂模式

1. 模式的功能

抽象工厂的功能是为一系列相关对象或相互依赖的对象创建一个接口,一定要注意,这个接口内的方法不是任意堆砌的,而是一系列相关或相互依赖的方法,比如上面例子中的CPU和主板,都是为了组装一台电脑的相关对象。

从某种意义上看,抽象工厂其实是一个产品系列,或者是产品簇。上面例子中的抽象工厂就可以看成是电脑簇,每个不同的装机方案,代表一种具体的电脑系列。

2. 实现成接口

AbstractFactory在Java中通常实现成为接口,大家不要被名称误导了,以为是实现成为抽象类,当然,如果需要为这个产品簇提供公共的功能,也不是不可以把AbstractFactory实现成为抽象类,但一般不这么做。

3. 使用工厂方法

AbstractFactory定义了创建产品所需要的接口,具体的实现是在实现类里面,通常在实现类里面就需要选择多种更具体的实现,所以AbstractFactory定义的创建产品的方法可以看成是工厂方法,而这些工厂方法的具体实现就延迟到了具体的工厂里面。也就是说使用工厂方法来实现抽象工厂

4. 切换产品簇

由于抽象工厂定义的一系列对象,通常是相关或者相依赖的,这些产品对象就构成了一个产品簇,也就是抽象工厂定义了一个产品簇。这就带来非常大的灵活性,切换一个产品簇的时候,只要提供不同的抽象工厂实现就好了,也就是说现在是以产品簇做为一个整体被切换

# 3.2 优缺点

1. 分离接口和实现

客户端使用抽象工厂来创建需要的对象,而客户端根本就不知道具体的实现是谁,客户端只是面向产品的接口编程而已,也就是说,客户端从具体的产品实现中解耦。

2. 使得切换产品簇变得容易

因为一个具体的工厂实现代表的是一个产品簇,比如上面例子的Scheme1代表装机方案一:Intel 的CPU + 技嘉的主板,如果要切换成为Scheme2,那就变成了装机方案二:AMD的CPU + 微星的主板。

客户端选用不同的工厂实现,就相当于是在切换不同的产品簇。

3. 不太容易扩展新的产品

前面也提到这个问题了,如果需要给整个产品簇添加一个新的产品,那么就需要修改抽象工厂,这样就会导致修改所有的工厂实现类。在前面提供了一个可以扩展工厂的方式来解决这个问题,但是又不够安全。如何选择,根据实际应用来权衡吧。

4. 容易造成类层次复杂

在使用抽象工厂模式的时候,如果需要选择的层次过多,那么会造成整个类层次变得复杂。

举个例子来说,就比如前面讲到的那个DAO的示例,现在这个DAO只有一个选择的层次,也就是选择一下是使用关系型数据库来实现,还是用Xml来实现。现在考虑这样一种情况,如果关系型数据库实现里面又分成几种,比如:基于Oracle的实现,基于SqlServer的实现,基于MySql的实现等等。

那么客户端怎么选呢?不会把所有可能的实现情况全部都做到一个层次上吧,这个时候客户端就需要一层一层选择,也就是整个抽象工厂的实现也需要分出层次来,每一层负责一种选择,也就是一层屏蔽一种变化,这样很容易造成复杂的类层次结构

# 3.3 思考抽象工厂模式

1. 抽象工厂模式的本质

抽象工厂模式的本质:选择产品簇的实现。

工厂方法是选择单个产品的实现,虽然一个类里面可以有多个工厂方法,但是这些方法之间一般是没有联系的,即使看起来像有联系

但是抽象工厂着重的就是为一个产品簇选择实现,定义在抽象工厂里面的方法通常是有联系的,它们都是产品的某一部分或者是相互依赖的。如果抽象工厂里面只定义一个方法,直接创建产品,那么就退化成为工厂方法了。

2. 何时选用抽象工厂模式

建议在如下情况中,选用抽象工厂模式:

如果希望一个系统独立于它的产品的创建,组合和表示的时候,换句话说,希望一个系统只是知道产品的接口,而不关心实现的时候。

如果一个系统要由多个产品系列中的一个来配置的时候,换句话说,就是可以动态的切换产品簇的时候。

如果要强调一系列相关产品的接口,以便联合使用它们的时候

# 3.4 相关模式

1. 抽象工厂模式和工厂方法模式

简单工厂是用来选择实现的,可以选择任意接口的实现,一个简单工厂可以有多个用于选择并创建对象的方法,多个方法创建的对象可以有关系也可以没有关系。

抽象工厂模式是用来选择产品簇的实现的,也就是说一般抽象工厂里面有多个用于选择并创建对象的方法,但是这些方法所创建的对象之间通常是有关系的,这些被创建的对象通常是构成一个产品簇所需要的部件对象。

所以从某种意义上来说,简单工厂和抽象工厂是类似的,如果抽象工厂退化成为只有一个实现,不分层次,那么就相当于简单工厂了

这两个模式既有区别,又有联系,可以组合使用。

2. 抽象工厂模式和单例模式

这两个模式可以组合使用。

在抽象工厂模式里面,具体的工厂实现,在整个应用中,通常一个产品系列只需要一个实例就可以了,因此可以把具体的工厂实现成为单例。

# 四:JDK

# 五:参考文献

最后更新: 3/25/2022, 11:35:07 AM