常用设计模式系列(三)—抽象工厂模式

一、前言

各位大佬好,又是一个冷嗖嗖的日子,这个城市的天气最近一直都不太好,说下雪吧也不下,天气也不晴,让人甚是难受。前段时间周围的城市都下雪了,盼了好久的雪也没盼到,只等来了冷风作祟。基于我的心情,我来吟诗一首:

​ 《盼雪》

昨日已别大雪,

吾昼夜盼雪至。

虽见细雨飘散,

气寒云彩密集。

盼雪之心已惫,

不见漫天飘零。

—— 作者:IT小白闯天下

​ 开始我们今天的模式讲解,前期我分别讲解了简单工厂模式和工厂方法模式,工厂方法模式对比简单工厂模式,是在原有基础上进行了升级,将负责每个产品的工厂进行拆分,每个工厂生产自己的产品,此时的工厂类是只能生产自己的产品的。那么抽象工厂是再次升级,抽象工厂可定义每个工厂生产的产品种类,每个工厂从只生产一种产品改为只生产一个系列的产品。

二、概念讲解

简单工厂模式:一个工厂生产所有产品。

工厂方法模式:每个工厂生产自己负责的具体产品。

抽象工厂模式:抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级(一个系列)的产品。

那么抽象工厂怎么理解?抽象工厂是在工厂方法的基础上再次进行升级,具体升级了什么,我来使用生活实例进行讲解。

一个手机公司,目前在生产一个新品手机,目前手机屏幕和电池都需要三方供应商来供货,前期合作的供应商能够满足所需,由于现在客户量群体越来越大,第一家供应商无法满足,则选择了签约了另一家供应商同时供货(我用的某果手机的基带就是这种模式),那么手机生产厂家(抽象工厂)就定义了两个规范,生产符合要求的电池(抽象产品)和符合要求的屏幕(抽象产品),这两个条件就可以理解为抽象方法,那么此时,在抽象工厂则拥有两个抽象方法,下面的两个工厂都需要生产手机电池(具体产品)和手机屏幕(具体产品),通过扩展抽象工厂内部抽象方法的方式来要求下面工厂完成要求。

上面使用的方式就是抽象工厂,将工厂方法模式中的一个工厂从生产一个产品改为生产一个系列产品。每个产品由多个产品工厂提供。

用例图:

抽象工厂方法模式构成:

1.抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。。

2.具体工厂(ConcreteFactory):主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

3.抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式支持多个抽象产品。

4.具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一关系。

可能有人会发现与工厂方法的构成类似,但是与工厂方法模式模式还是区别很大的,区别点如下:

1.抽象工厂有多个创建产品的方法,而工厂方法模式只有一个

2.抽象工厂模式是有多个抽象产品,工厂方法模式只有一个

3.抽象工厂模式中具体工厂跟具体产品之间是一对多,但是工厂方法是一对一。

UML图

三、代码实现

1.创建抽象产品A——电池抽象产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.yang.abstractfactory.product;

/**

- @ClassName AbstractProductA
- @Description 抽象产品A
- @Author IT小白架构师之路
- @Date 2020/12/8 18:04
- @Version 1.0
**/
public interface AbstractPower {
/**
- 蓄电的抽象方法
*/
public void recharge();
}
}

2.创建抽象产品B——屏幕抽象产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.yang.abstractfactory.product;

/**
* @ClassName AbstractProductB
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 18:05
* @Version 1.0
**/
public interface AbstractScreen {
/**
* 抽象方法显示
*/
public void light();
}

3.创建具体电池产品,A工厂生产的电池产品和B工厂生产的电池产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.yang.abstractfactory.product;

/**
* @ClassName PowerA
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 18:09
* @Version 1.0
**/
public class PowerA implements AbstractPower{
@Override
public void recharge() {
System.out.println("我是A厂商的电池,我可以蓄电");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.yang.abstractfactory.product;

/**
* @ClassName PowerB
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 18:09
* @Version 1.0
**/
public class PowerB implements AbstractPower{
@Override
public void recharge() {
System.out.println("我是B厂商的电池,我可以蓄电");
}
}

4.创建具体屏幕产品,B工厂生产的屏幕产品和B工厂生产的屏幕产品

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.yang.abstractfactory.product;

/**
* @ClassName ScreenA
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 18:10
* @Version 1.0
**/
public class ScreenA implements AbstractScreen {
@Override
public void light() {
System.out.println("我是A厂商的屏幕,我可以显示图片");
}
}

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
package com.yang.abstractfactory.product;

/**
* @ClassName ScreenB
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 18:10
* @Version 1.0
**/
public class ScreenB implements AbstractScreen {
@Override
public void light() {
System.out.println("我是B厂商的屏幕,我可以显示图片");
}
}


5.创建抽象工厂
package com.yang.abstractfactory.factory;

import com.yang.abstractfactory.product.AbstractPower;
import com.yang.abstractfactory.product.AbstractScreen;

/**
* @ClassName AbstractFactory
* @Description 抽象工厂
* @Author IT小白架构师之路
* @Date 2020/12/8 20:43
* @Version 1.0
**/
public interface AbstractFactory {
/**
* 创建产品A的抽象方法
* @return
*/
public AbstractPower createPower();

/**
* 创建产品B的抽象方法
* @return
*/
public AbstractScreen createScreen();

}

6.创建具体工厂A和具体工厂B

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
package com.yang.abstractfactory.factory;


import com.yang.abstractfactory.product.AbstractPower;
import com.yang.abstractfactory.product.AbstractScreen;
import com.yang.abstractfactory.product.PowerA;
import com.yang.abstractfactory.product.ScreenA;

/**
* @ClassName ConcreteProductFactoryA
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 20:07
* @Version 1.0
**/
public class ConcreteProductFactoryA implements AbstractFactory{
@Override
public AbstractPower createPower() {
return new PowerA();
}

@Override
public AbstractScreen createScreen() {
return new ScreenA();
}
}

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

package com.yang.abstractfactory.factory;

import com.yang.abstractfactory.product.*;

/**
* @ClassName ConcreteProductFactoryB
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 20:39
* @Version 1.0
**/
public class ConcreteProductFactoryB implements AbstractFactory {
@Override
public AbstractPower createPower() {
return new PowerB();
}

@Override
public AbstractScreen createScreen() {
return new ScreenB();
}
}

7.创建客户端,分别测试A工厂和B工厂生产电池,同时测试A工厂B工厂生产屏幕

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
package com.yang.abstractfactory.clent;

import com.yang.abstractfactory.factory.AbstractFactory;
import com.yang.abstractfactory.factory.ConcreteProductFactoryA;
import com.yang.abstractfactory.factory.ConcreteProductFactoryB;
import com.yang.abstractfactory.product.AbstractPower;
import com.yang.abstractfactory.product.AbstractScreen;

/**
* @ClassName Client
* @Description 注释
* @Author IT小白架构师之路
* @Date 2020/12/8 20:40
* @Version 1.0
**/
public class Client {
public static void main(String[] args) {
//使用A工厂创建电池产品
AbstractFactory factory = new ConcreteProductFactoryA();
AbstractPower power = factory.createPower();
power.recharge();
//使用A工厂创建屏幕产品
AbstractScreen screen = factory.createScreen();
screen.light();
//使用B工厂创建电池产品
factory = new ConcreteProductFactoryB();
power = factory.createPower();
power.recharge();
//使用A工厂创建屏幕产品
screen = factory.createScreen();
screen.light();
}
}

8.测试结果如下

1
2
3
4
我是A厂商的电池,我可以蓄电
我是A厂商的屏幕,我可以显示图片
我是B厂商的电池,我可以蓄电
我是B厂商的屏幕,我可以显示图片

9.抽象工厂全家类合辑

四、抽象工厂方法模式优缺点及适用场景

优点:

1.抽象工厂隔离了具体类的创建过程,不需要知道怎么创建,由于隔离,当需要更换工厂时,只需要选择实现了抽象工厂并实现了定义的抽象方法的具体工厂即可,可以通过改变工厂的方式改变软线系统的行为。

2.当一个产品族的多个对象被设计到一起工作时,抽象工厂可以保证客户端始终只是用同一个产品族的对象。

3.容易扩展产品族

缺点:

如果要增加新的产品分类,则需要对原有系统进行较大的修改,需要动到抽象层,会违背开闭原则。

解释:

新的产品族:同一个产品由不同厂商提供,就是属于同一个产品族

新的产品分类:新的产品类型

###适用场景

1.一个系统不需要关心具体对象创建过程,需要将对象创建和使用进行解耦时。

2.系统中有多个产品族,每次只是用其中某一种产品族时。

3.属于同一种产品族的产品放一起使用时(例如A工厂的电池和B工厂的电池都被手机厂使用时)。

4.产品分类固定,设计之后不会再增加产品分类时,