工厂模式
# 工厂模式
工厂模式是一种对象创建型模式,它提供了一种创建对象的最佳实践。在工厂模式中,我们在创建对象时不使用 new 关键字,而是通过调用工厂方法来创建对象。工厂方法可以返回不同的对象类型,因此工厂模式可以创建一组相关或不相关的对象。这样就可以将对象的创建和使用解耦。选择使用哪种工厂模式取决于具体的需求和场景,例如产品数量、产品关系、扩展性等因素。
工厂模式有三种:简单工厂模式、工厂方法模式和抽象工厂模式。
- img: https://bitouyun.com/images/design-pattern/simple-factory.png
link: https://bitouyun.com/images/design-pattern/simple-factory.png
name: 简单工厂模式
- img: https://bitouyun.com/images/design-pattern/factory-method.png
link: https://bitouyun.com/images/design-pattern/factory-method.png
name: 工厂方法模式
- img: https://bitouyun.com/images/design-pattern/multiple-factory.png
link: https://bitouyun.com/images/design-pattern/multiple-factory.png
name: 多工厂方法模式
2
3
4
5
6
7
8
9
# 定义
简单工厂模式:
简单工厂模式通过一个工厂类,根据不同的参数来创建不同的产品类的实例。
工厂方法模式:
通过定义一个创建产品的抽象方法,在具体的工厂类中实现该方法来创建具体的产品对象。
抽象工厂模式:
提供一个接口或抽象类,用于创建一系列相关或相互依赖的产品对象,而无需指定具体的类。
# 区别
简单工厂模式:简单工厂模式只包含一个工厂类,它负责根据参数来创建产品类的实例,客户端只需要知道工厂类的接口和参数即可获取所需的产品对象。
工厂方法模式:工厂方法模式将产品的创建延迟到具体的工厂类中,每个具体工厂类负责创建特定的产品对象,客户端通过调用具体工厂类来获取所需的产品对象。
抽象工厂模式:抽象工厂模式关注一组相关产品对象的创建,每个具体工厂类负责创建一组特定的产品对象,客户端通过调用具体工厂类来获取所需的产品对象。
# 优点
可以将对象的创建和使用解耦,从而提高系统的灵活性和可维护性。
工厂模式可以隐藏对象的创建细节,使客户端只关心对象的使用,从而降低系统的复杂度。
工厂模式可以实现开闭原则,当需要增加新的产品时,只需要增加相应的工厂类即可,无需修改原有代码。
# 缺点
工厂模式会增加系统中类的数量,当产品类型较多时,会导致系统过于庞大和复杂。
工厂模式需要引入抽象层,这会增加系统的抽象性和理解难度。
# 应用场景
简单工厂模式: 适用于产品较少且创建逻辑相对简单的场景,可以将对象的创建逻辑集中在工厂类中,提供统一的创建接口给客户端。
工厂方法模式:适用于需要创建多个相关产品对象的场景,每个产品对象由对应的具体工厂类创建,客户端可以选择使用不同的具体工厂类来创建不同的产品对象。
常见领域应用场景
框架和库:许多软件框架和库使用工厂方法模式来创建对象。例如,在Java中,Java集合框架中的ArrayList和LinkedList等容器类都是通过List接口的工厂方法List.of()来创建的。这样,客户端代码可以使用通用的List接口,而无需关心具体实现类。
日志记录器:在日志记录器的实现中,可以使用工厂方法模式来创建不同类型的日志记录器。例如,可以定义一个Logger接口,并通过具体的工厂类(如FileLoggerFactory、DatabaseLoggerFactory)来创建不同类型的日志记录器(如文件日志记录器、数据库日志记录器)。
数据库访问:在数据库访问层中,工厂方法模式可以用于创建数据库连接对象或执行数据库查询的对象。不同的数据库引擎可能需要不同的连接对象,而使用工厂方法模式可以根据具体的数据库类型来创建相应的对象。
插件系统:工厂方法模式可以用于实现插件系统,其中插件接口定义了通用的功能,而具体的插件工厂类负责创建不同类型的插件对象。这样,可以通过配置或其他方式来选择使用哪个插件工厂类,从而实现动态加载和扩展功能。
游戏开发:在游戏开发中,工厂方法模式常用于创建游戏中的各种对象,如角色、武器、道具等。通过使用工厂方法模式,可以根据游戏的需求和规则来创建不同类型的游戏对象。
抽象工厂模式:适用于需要创建多个相关产品对象的场景,每个产品对象由对应的具体工厂类创建,客户端可以选择使用不同的具体工厂类来创建不同的产品对象,并且产品对象之间存在一定的关联或依赖关系。
常见领域应用场景
数据库访问:在数据库访问层中,可以使用抽象工厂模式来创建特定数据库的连接对象、命令对象等。不同类型的数据库(如MySQL、Oracle、SQL Server等)可以有各自的具体工厂实现,以创建特定数据库的对象。
操作系统封装:在操作系统封装或跨平台开发中,可以使用抽象工厂模式来创建特定操作系统的对象,如文件操作、进程管理等。不同操作系统(如Windows、Linux、Mac等)可以有各自的具体工厂实现,以创建特定操作系统的对象。
加密算法:在加密算法库中,可以使用抽象工厂模式来创建不同类型的加密算法对象,如对称加密算法(如AES、DES)、非对称加密算法(如RSA)等。不同类型的加密算法可以有各自的具体工厂实现,以创建特定类型的加密算法对象。
网络通信:在网络通信库中,可以使用抽象工厂模式来创建不同类型的网络连接对象、数据传输对象等。不同协议(如TCP、UDP、HTTP)可以有各自的具体工厂实现,以创建特定协议的对象。
游戏开发:在游戏开发中,可以使用抽象工厂模式来创建不同类型的游戏角色、武器、道具等。不同类型的角色或道具可以有各自的具体工厂实现,以创建特定类型的游戏对象。
# 示例代码1
场景1:简单工厂模式、工厂方法模式
女娲造人: 黄种人、白种人和黑种人。
/**
* 人类接口
*/
public interface Human {
// 肤色
void getColor();
// 语言
void talk();
}
/**
* 黄种人
*/
public class YellowHuman implements Human {
@Override
public void getColor() {
System.out.println("黄色人种的皮肤是黄色的");
}
@Override
public void talk() {
System.out.println("黄色人种会说话,一般说的都是双字节");
}
}
/**
* 白种人
*/
public class WhiteHuman implements Human {
@Override
public void getColor() {
System.out.println("白色人种的皮肤颜色是白色的");
}
@Override
public void talk() {
System.out.println("白色人种会说话,一般都是单字节");
}
}
/**
* 黑种人
*/
public class BlackHuman implements Human {
@Override
public void getColor() {
System.out.println("黑色人种的皮肤颜色是黑色的");
}
@Override
public void talk() {
System.out.println("黑人会说话,一般人听不懂");
}
}
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
/**
* 简单工厂类(静态工厂类)
* 八卦炉
*/
public class StaticHumanFactory {
public static <T extends Human> T createHuman(Class<T> c) {
Human human = null;
try {
// human = (Human) Class.forName(c.getName()).newInstance(); // java8
human = (Human) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); // java9+
} catch (Exception e) {
System.out.println("人种生成错误");
}
return (T) human;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 工厂方法实现类
* 八卦炉
*/
public class HumanFactory extends AbstractHumanFactory {
@Override
public <T extends Human> T createHuman(Class<T> c) {
Human human = null;
try {
// human = (Human) Class.forName(c.getName()).newInstance(); // java8
human = (Human) Class.forName(c.getName()).getDeclaredConstructor().newInstance(); // java9+
} catch (Exception e) {
System.out.println("人种生成错误");
}
return (T) human;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 多工厂模式抽象工厂类型
* 八卦炉
*/
public abstract class MultipleAbstractHumanFactory {
// 抽象方法中不需要传递参数,因为每一个具体的工厂都已经非常明确自己的职责,创建自己负责的产品类对象
public abstract Human createHuman();
}
/**
* 黄色人种的创建工厂类
*/
public class MultipleYellowHumanFactory extends MultipleAbstractHumanFactory {
@Override
public Human createHuman() {
return new YellowHuman();
}
}
/**
* 白色人种的创建工厂类
*/
public class MultipleWhiteHumanFactory extends MultipleAbstractHumanFactory {
@Override
public Human createHuman() {
return new WhiteHuman();
}
}
/**
* 黑色人种的创建工厂实现类
*/
public class MultipleBlackHumanFactory extends MultipleAbstractHumanFactory {
@Override
public Human createHuman() {
return new BlackHuman();
}
}
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
/**
* 测试类
* 女娲
*/
@Slf4j
public class Client {
public static void main(String[] args) {
log.info("工厂方法模式========");
AbstractHumanFactory abstractHumanFactory = new HumanFactory();
WhiteHuman whiteHuman = abstractHumanFactory.createHuman(WhiteHuman.class);
whiteHuman.getColor();
whiteHuman.talk();
BlackHuman blackHuman = abstractHumanFactory.createHuman(BlackHuman.class);
blackHuman.getColor();
blackHuman.talk();
YellowHuman yellowHuman = abstractHumanFactory.createHuman(YellowHuman.class);
yellowHuman.getColor();
yellowHuman.talk();
// 简单工厂模式(静态工厂模式) 优点:简单实用; 缺点:工厂类扩展比较困难,不符合开闭原则,但是一个非常实用的设计模式
log.info("简单工厂模式========");
WhiteHuman staticWhiteHuman = StaticHumanFactory.createHuman(WhiteHuman.class);
staticWhiteHuman.getColor();
staticWhiteHuman.talk();
// 多工厂模式 每个产品对应一个创建类,优点:职责清晰,结构简单
// 缺点:可扩展、可维护性带来一定的影响,如果要扩展一个产品类,就需要建立一个相应的工厂类,增加了扩展的难度,
// 在复杂应用中一般采用多工厂方法,再增加一个协调类,避免调用者与各个子工厂交流,协调类封装子工厂类,对高层模块提供统一的访问接口
log.info("多工厂模式========");
Human multipleWhiteHuman = new MultipleWhiteHumanFactory().createHuman();
multipleWhiteHuman.getColor();
multipleWhiteHuman.talk();
}
}
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
// Make sure to add code blocks to your code group
# 示例代码2
场景2:简单工厂模式、工厂方法模式
生产A、B两种产品
/**
* 父级产品接口
*/
public interface ParentProduct {
void printName();
}
/**
* 产品A
*/
public class ProductA implements ParentProduct {
@Override
public void printName() {
System.out.println("product A");
}
}
/**
* 产品B
*/
public class ProductB implements ParentProduct {
@Override
public void printName() {
System.out.println("product B");
}
}
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
/**
* 静态工厂方法模式(简单工厂模式)
*/
public class StaticProductFactory {
public static ParentProduct produceA() {
return new ProductA();
}
public static ParentProduct produceB() {
return new ProductB();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 抽象产品工厂类
*/
public class NormalProductFactory {
public ParentProduct produce(String name) {
if ("A".equals(name)) {
return new ProductA();
} else if ("B".equals(name)) {
return new ProductB();
}
return null;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 多个产品工厂方法模式
*
*/
public class MultipleProductFactory {
public ParentProduct produceA() {
return new ProductA();
}
public ParentProduct produceB() {
return new ProductB();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 静态工厂方法模式: 将工厂方法设置为静态方法,不需要创建实例,直接调用
ParentProduct staticProductA = StaticProductFactory.produceA();
staticProductA.printName();
// 普通工厂模式:建立一个工厂类(ProductFactory),对实现同一接口(ParentProduct)的类进行实例的创建
NormalProductFactory normalFactory = new NormalProductFactory();
ParentProduct productA = normalFactory.produce("A");
productA.printName();
// 多个工厂方法模式: 提供多个工厂方法,分别创建对象
MultipleProductFactory multipleFactory = new MultipleProductFactory();
ParentProduct productB = multipleFactory.produceB();
productB.printName();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Make sure to add code blocks to your code group
# 抽象工厂示例
场景3: 抽象工厂模式
不同操作系统渲染不同用户界面组件,如按钮、文本框等。
- img: https://bitouyun.com/images/design-pattern/abstract-factory.png
link: https://bitouyun.com/images/design-pattern/abstract-factory.png
name: 抽象工厂模式
2
3
/**
* GUI抽象工厂接口
*/
public interface GUIFactory {
/**
* 创建按钮
*/
Button createButton();
/**
* 创建文本框
*/
TextField createTextField();
}
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Windows操作系统具体工厂类
*/
@Slf4j
public class WindowsGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new WindowsButton();
}
@Override
public TextField createTextField() {
return new WindowsTextField();
}
}
/**
* Mac操作系统具体工厂类
*/
@Slf4j
public class MacGUIFactory implements GUIFactory {
@Override
public Button createButton() {
return new MacButton();
}
@Override
public TextField createTextField() {
return new MacTextField();
}
}
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
/**
* 按钮接口
*/
public interface Button {
void render();
}
/**
* Windows按钮
*/
@Slf4j
public class WindowsButton implements Button{
@Override
public void render() {
log.info("渲染Windows按钮");
}
}
/**
* Mac风格按钮
*/
@Slf4j
public class MacButton implements Button{
@Override
public void render() {
log.info("渲染Mac风格按钮");
}
}
/**
* 文本框
*/
public interface TextField {
void render();
}
/**
* Windows风格文本框
*/
@Slf4j
public class WindowsTextField implements TextField{
@Override
public void render() {
log.info("渲染Windows风格文本框");
}
}
/**
* Mac风格文本框
*/
@Slf4j
public class MacTextField implements TextField{
@Override
public void render() {
log.info("渲染Mac风格文本框");
}
}
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
/**
* 测试类
*/
public class Client {
public static void main(String[] args) {
// 创建Windows风格按钮和文本框
WindowsGUIFactory windowsGUIFactory = new WindowsGUIFactory();
Button windowsButton = windowsGUIFactory.createButton();
windowsButton.render();
TextField windowsTextField = windowsGUIFactory.createTextField();
windowsTextField.render();
// 创建Mac风格按钮和文本框
MacGUIFactory macGUIFactory = new MacGUIFactory();
Button macButton = macGUIFactory.createButton();
macButton.render();
TextField macTextField = macGUIFactory.createTextField();
macTextField.render();
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Make sure to add code blocks to your code group