创建式:抽象工厂

1 基本介绍

​ 前面介绍过,工厂方法每个工厂只能生产一个产品,会导致系统存在大量的工厂类,增加系统的开销。此时,可以将一些相关的产品组成一个“产品族”,由同一个工厂来生产。这就是抽象工厂的基本思想。

​ 也就是说,一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,可以生产电视机,冰箱,空调等。

引入两个概念

产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。

产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中,海尔电视机、海尔电冰箱构成了一个产品族。

image-20220314124831786

​ 我们只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一确定这个产品。

​ 抽象工厂模式通常是用于创建不同产品等级结构的一个产品族中的所有对象

image-20220314125346599

2 设计分析

​ 开发一套界面皮肤库,皮肤库代码不打算公开,用户通过菜单选择皮肤,不同皮肤提供不同按钮,文本框等

image-20220314125651230

2.1 工厂方法设计

image-20220314125704964

​ 可以发现,该设计存在如下问题

  1. 虽然增加类时不需要修改原有代码,可是要增加大量类,导致系统越来越庞大
  2. 每个组件都需要选择一个具体工厂,选择失误很容易导致界面显示混乱

2.2 抽象工厂设计

image-20220314130048403

代码大概如下

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package DesignPatterns.JavaDesign.AbstractFactory;

import DesignPatterns.JavaDesign.FactoryMethod.XMLUtil;

public class Test {
public static void main(String[] args) {
//使用抽象层定义
SkinFactory factory;
Button bt;
TextField tf;
ComboBox cb;
// 可以改为使用配置文件
factory = new SummerSkinFactory();
bt = factory.createButton();
tf = factory.createTextField();
cb = factory.createComboBox();
bt.display();
tf.display();
cb.display();
}
}

/**
* 按钮接口:抽象产品
*/
interface Button {
public void display();
}

// Spring按钮类:具体产品
class SpringButton implements Button {
@Override
public void display() {
System.out.println("显示浅绿色按钮。");
}
}

class SummerButton implements Button {
@Override
public void display() {
System.out.println("显示浅蓝色按钮");
}
}

/**
* 文本框接口∶抽象产品
*/
interface TextField {
public void display();
}

// Spring文本框类∶具体产品
class SpringTextField implements TextField {
public void display() {
System.out .println( "显示绿色边框文本框。");
}
}

// Summer文本框类∶具体产品
class SummerTextField implements TextField {
public void display() {
System.out .println ( "显示蓝色边框文本框。");
}
}

/**
* 组合框接口∶抽象产品
*/
interface ComboBox {
public void display( );
}

// Spring组合框类∶具体产品
class SpringComboBox implements ComboBox {
public void display() {
System.out.println( "显示绿色边框组合框。");
}
}

// Summer组合框类︰具体产品
class SummerComboBox implements ComboBox {
public void display() {
System.out.println ( "显示蓝色边框组合框。");
}
}

/**
* 界面皮肤工厂接口∶抽象工厂
*/
interface SkinFactory {
public Button createButton();
public TextField createTextField ();
public ComboBox createComboBox();
}

// Spring皮肤工厂:具体工厂
class SpringSkinFactory implements SkinFactory {
public Button createButton( ) {
return new SpringButton( );
}
public TextField createTextField() {
return new SpringTextField ();
}
public ComboBox createComboBox(){
return new SpringComboBox( );
}
}

// Summer皮肤工厂:具体工厂
class SummerSkinFactory implements SkinFactory {
public Button createButton() {
return new SummerButton();
}
public TextField createTextField() {
return new SummerTextField();
}
public ComboBox createComboBox() {
return new SummerComboBox();
}
}

​ 如果需要更改皮肤,只需修改配置文件即可。

3 总结

优缺点分析

优点:

  1. 隔绝了具体类的生成
  2. 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。
  3. 增加新的产品族很方便,无须修改已有系统,符合“开闭原则”。

缺点:

  1. 增加新的产品等级结构麻烦,需要对原有系统进行较大的修改,甚至需要修改抽象层代码,这显然会带来较大的不便,违背了“开闭原则”。

适用场景

  1. 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
  2. 系统中有多于一个的产品族,而每次只使用其中某一产品族
  3. 属于同一个产品族的产品将在一起使用
  4. 产品等级结构稳定

4 场景使用

4.1 BeanFactory在Spring中的使用

​ 在 Spring 中,BeanFactory 是用于管理 Bean 的一个工厂,所有工厂都是 BeanFactory 的子类。这样我们可以通过 IOC 容器来管理访问 Bean,根据不同的策略调用 getBean() 方法,从而获得具体对象。

​ BeanFactory 接口的源码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface BeanFactory {
String FACTORY_BEAN_PREFIX = "&";
Object getBean(String name) throws BeansException;
<T> T getBean(String name, @Nullable Class<T> requiredType) throws BeansException;
Object getBean(String name, Object... args) throws BeansException;
<T> T getBean(Class<T> requiredType) throws BeansException;
<T> T getBean(Class<T> requiredType, Object... args) throws BeansException;
boolean containsBean(String name);
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
boolean isPrototype(String name) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, ResolvableType typeToMatch) throws NoSuchBeanDefinitionException;
boolean isTypeMatch(String name, @Nullable Class<?> typeToMatch) throws NoSuchBeanDefinitionException;
@Nullable
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
String[] getAliases(String name);
}
 `BeanFactory`的子类主要有 `ClassPathXmlApplicationContext`、`XmlWebApplicationContext`、`StaticWebApplicationContext`、`StaticApplicationContext`。在 Spring 中,`DefaultListableBeanFactory`实现了所有工厂的公共逻辑。

参考

《Java设计模式》——刘伟

(109条消息) 抽象工厂模式在spring源码中的应用_蒙奇D灬小武的博客-CSDN博客_抽象工厂模式在spring的应用


创建式:抽象工厂
https://2w1nd.github.io/2022/03/14/设计模式/创建式:抽象工厂/
作者
w1nd
发布于
2022年3月14日
许可协议