设计模式-抽象工厂模式

在前面介绍的工厂方法模式是考虑的一类产品的生产,如手机工厂只生产手机,也就是说,工厂方法模式只考虑生产同等级产品,但是在现实生活中,许多工厂是综合型的工厂,手机工厂不仅仅只生产手机,还生产耳机、手机壳、充电宝等等

本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族

抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一类

1 模式介绍

1.1 定义

抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

1.2 模式组成

抽象工厂模式的主要角色如下。

组成(角色) 关系 作用
抽象产品(Product) 具体产品的父类 描述具体产品的公共接口
具体产品(Concrete Product) 抽象产品的子类;工厂类创建的目标类 描述生产的具体产品
抽象工厂(Creator) 具体工厂的父类 描述具体工厂的公共接口
具体工厂(Concrete Creator) 抽象工厂的子类;被外界调用 描述具体工厂;实现FactoryMethod工厂方法创建产品的实例

从图上面的图可以看出抽象工厂模式的结构同工厂方法模式的结构相似,不同的是其产品的种类不止一个,所以创建产品的方法也不止一个。

1.3 解决的问题

解决工厂方法模式的缺点

每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度,工厂方法可以解决这一问题

2 实例讲解:

继续工厂方法模式中手机专卖店Store卖手机的例子,不了解的可以去看看工厂方法模式中手机专卖店的例子。目前Store卖有两种手机,一个苹果手机,一个索尼手机,此时客户需要买耳机,那么专卖店就必须要进货,采购不同厂商品牌的耳机(苹果耳机、索尼耳机)。那么就必须要新增耳机工厂(苹果耳机工厂、索尼耳机工厂),而且还是不同品牌的耳机,假如后面又增加了一个品牌(比如小米)的手机、耳机、充电器、手机壳,此时使用工厂方法模式就要增加小米手机工厂、耳机工厂、充电器工厂、手机壳工厂,想想对这一大堆工厂的管理就很麻烦,那么使用抽象工厂模式就能解决这种问题

2.1 使用步骤

步骤1: 创建抽象产品类 ,定义具体产品的公共抽象接口;

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
/**
* 耳机
*
* @author mrxccc
* @create 2020/9/23
*/
public abstract class Headset {
/**
* 品牌
*/
protected String brand;

abstract void play();

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}
}


/**
* @author mrxccc
* @create 2020/9/23
*/
public abstract class Phone {
/**
* 品牌
*/
protected String brand;

/**
* 操作系统
*/
protected String os;

/**
* 充电
*/
public abstract void charge();

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

public String getOs() {
return os;
}

public void setOs(String os) {
this.os = os;
}
}

步骤2: 创建抽象工厂类,定义具体工厂的公共接口

1
2
3
4
5
6
7
8
9
10
/** 
* 这里和工厂方法模式不同,定义了同一等级的不同产品
* @author mrxccc
* @create 2020/9/23
*/
public interface Factory {
Phone getPhone();

Headset getHeadset();
}

步骤3:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;

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
/**
* 苹果工厂
* @author mrxccc
* @create 2020/9/23
*/
public class AppleFactory implements Factory{
@Override
public ApplePhone getPhone() {
ApplePhone applePhone = new ApplePhone();
applePhone.setBrand("Apple");
return applePhone;
}

@Override
public AppleHeadset getHeadset() {
AppleHeadset appleHeadset = new AppleHeadset();
appleHeadset.setBrand("Apple");
return appleHeadset;
}

}

/**
* 索尼工厂
*
* @author mrxccc
* @create 2020/9/23
*/
public class SonyFactory extends Factory {
@Override
public SonyPhone getPhone() {
SonyPhone sonyPhone = new SonyPhone();
sonyPhone.setBrand("Sony");
return sonyPhone;
}

@Override
public SonyHeadset getHeadset() {
SonyHeadset sonyHeadset = new SonyHeadset();
sonyHeadset.setBrand("Sony");
return sonyHeadset;
}

}

步骤4: 创建抽象产品类

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
/**
* @author mrxccc
* @create 2020/9/23
*/
public abstract class Phone {
/**
* 品牌
*/
protected String brand;

/**
* 操作系统
*/
protected String os;

/**
* 充电
*/
public abstract void charge();

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

public String getOs() {
return os;
}

public void setOs(String os) {
this.os = os;
}
}

/**
* 耳机
*
* @author mrxccc
* @create 2020/9/23
*/
public abstract class Headset {
/**
* 品牌
*/
protected String brand;

abstract void play();

public String getBrand() {
return brand;
}

public void setBrand(String brand) {
this.brand = brand;
}

}

步骤5: 创建具体产品类(继承抽象产品类), 定义生产的具体产品;

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
/**
* 苹果手机
*
* @author mrxccc
* @create 2020/9/23
*/
public class ApplePhone extends Phone {
@Override
public void charge() {
System.out.println("普通充电");
}
}
/**
* 索尼手机
*
* @author mrxccc
* @create 2020/9/23
*/
public class SonyPhone extends Phone {
@Override
public void charge() {
System.out.println("快充");
}
}
/**
* 苹果耳机
* @author mrxccc
* @create 2020/9/23
*/
public class AppleHeadset extends Headset{
@Override
void play() {
// Apple 耳机播放逻辑 ...
System.out.println("Apple 耳机播放完成");
}
}
/**
* 索尼耳机
*
* @author mrxccc
* @create 2020/9/23
*/
public class SonyHeadset extends Headset {
@Override
void play() {
// Sony 耳机播放逻辑...
System.out.println("Sony 耳机播放完成");
}
}

步骤6:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例

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
/**
* 专卖店D:抽象工厂模式
* @author mrxccc
* @create 2020/9/23
*/
public class StoreD {
private Factory factory;

public StoreD(Factory factory) {
super();
this.factory = factory;
}

/**
* 补充手机
*/
public void supplyPhone() {
Phone phone = factory.getPhone();
// 补充手机逻辑...
System.out.println("补充" + phone.getBrand() + "手机完成");
}

/**
* 补充耳机
*/
public void supplyHeadset() {
Headset headset = factory.getHeadset();
// 补充耳机逻辑...
System.out.println("补充" + headset.getBrand() + "耳机完成");
}

public static void main(String[] args) {
StoreD storeC = new StoreD(new SonyFactory());
storeC.supplyPhone();
storeC.supplyHeadset();
}
}

结果

1
2
补充Sony手机完成
补充Sony耳机完成

3.应用场景

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

4.模式扩展

抽象工厂模式的扩展有一定的“开闭原则”倾斜性:

  1. 当增加一个新的产品族(是产品族,不是某个产品)时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  2. 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。

另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。

源码:设计模式

其他设计模式介绍:

设计模式-工厂方法模式

设计模式-抽象工厂模式

设计模式-建造者模式

更多精彩内容:mrxccc