工厂方法模式(Factory Method Pattern)

概述

工厂方法模式(Factory Method Pattern)是一个对象创建型模式。它提供了一种将对象的创建逻辑抽象出来的方式,使得客户端代码不需要关心具体的对象创建细节,而是通过调用工厂方法来创建对象。这种模式有助于解耦对象的创建和使用,同时也提供了扩展和定制对象创建过程的灵活性。

在工厂方法模式中,通常会定义一个抽象工厂接口,其中包含一个用于创建产品对象的抽象方法。具体的产品类需要实现这个工厂接口,并提供自己的产品创建逻辑。客户端代码通过调用工厂方法来创建所需的产品对象,而无需关心具体的产品类。

定义

Define an interface for creating an object, but let subclasses decide which class to instantiate.
Factory Method lets a class defer instantiation to subclasses

定义一个用于创建对象的接口,让子类决定实例化哪一个类。 Factory Method使一个类的实例化延迟到其子类。

引用自《设计模式:可复用面向对象软件的基础》

说的更直白一点就是,定义一个工厂接口,将对象的实例化操作放到工厂的实现类中。

结构

$2DrinkDrinkFactorygetDrink(): DrinkMilkyTeaCocoDrinkFactorygetDrink(): DrinkCocaCocaDrinkFactorygetDrink(): Drink可口可乐Coco奶茶店生产MilkyTea可口可乐工厂生产Coca

这个例子中有饮品 Drink 和饮品工厂 DrinkFactoryDrinkFactory 负责生产 Drink。在现实生活中可口可乐(Coca)和奶茶(MilkyTea),不是由一家生产的,而是生产可口可乐的工厂生产可口可乐,Coco奶茶店可以生产奶茶。

当我们需要奶茶饮品的时候就需要用 CocoDrinkFactory 生产,当我们需要可口可乐的时候就需要用 CocaDrinkFactory 生产。

这个例子不太恰当,因为我们不会直接从可口可乐工厂购买可口可乐。但是我认为用这个例子来解释工厂方法模式是没有问题的。而且能够清晰的描述出工厂方法模式的使用场景。

实现

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
public interface Drink {
}

public interface DrinkFactory {
Drink getDrink();
}

public class MilkyTea implements Drink {
}

public class Coca implements Drink {
}

public class CocoDrinkFactory implements DrinkFactory {

public Drink getDrink() {
return new MilkyTea();
}
}

public class CocaDrinkFactory implements DrinkFactory {

public Drink getDrink() {
return new Coca();
}
}

在开源框架中的应用

工厂方法模式在日志框架中的应用

工厂方法模式的一个典型应用场景是日志,准确的说是slf4j,这是一个日志的标准接口框架。其有着不同的实现,如logback, log4j。slf4j中的几个核心类

  • org.slf4j.Logger:接口,是具体的日志输出的实现。不同的日志框架有不同的实现。
  • org.slf4j.ILoggerFactory:接口,日志工厂,用于创建 Logger。不同的日志框架有不同的实现,但是只是创建自己框架内的 Logger
  • org.slf4j.LoggerFactory:类,用于获取 org.slf4j.ILoggerFactory
  • org.slf4j.spi.SLF4JServiceProvider:用于创建org.slf4j.ILoggerFactory,不是本章的重点。在以后的日志框架分析文章中再做说明。
  • java.util.ServiceLoader:用于通过ClassLoader发现org.slf4j.spi.SLF4JServiceProvider,也不是本章的重点。

上图是logbackslf4j的实现。org.slf4j.LoggerFactory 通过 ServiceLoader 发现logback的对org.slf4j.spi.SLF4JServiceProvider的实现ch.qos.logback.classic.spi.LogbackServiceProvider。然后通过 SLF4JServiceProvider.getLoggerFactory()获取org.slf4j.ILoggerFactory。然后再调用LoggerFactory.getLogger()创建org.slf4j.Logger

其他的日志框架,如log4jslf4j的实现方式也是类似的。我们一般不能在一个系统中引入两套日志框架,否则会出现org.slf4j.LoggerFactory不知道使用哪个ILoggerFactory的实现的情况。

Spring框架中工厂方法模式的应用

在Spring中FactoryBean就是使用了工厂方法模式的设计思想。Spring中的FactoryBean接口允许用户自定义工厂bean,用于创建和管理对象实例。通过实现FactoryBean接口,用户可以定义自己的工厂方法逻辑,实现对象的创建和初始化。

org.springframework.context.support.ConversionServiceFactoryBean

FactoryBean中可以实现复杂的对象创建逻辑,用户也可以定义一些配置选项,从而更灵活地定制对象的创建和初始化过程。

何时使用

在下列情况下可以使用Factory Method模式:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定它所创建的对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

与简单工厂模式的区别

  1. 简单工厂模式(Simple Factory Pattern):在简单工厂模式中,有一个工厂类,该工厂类提供一个方法,根据传入的参数来创建并返回不同类型的对象实例。客户端只需要知道所需对象的参数,而不需要关心对象的创建过程。
  2. 工厂方法模式(Factory Method Pattern):工厂方法模式通过定义一个创建对象的接口,但是将实际创建工作推迟到子类中。这样每个子类都可以重写这个工厂方法以返回不同的对象类型,从而使得客户端可以通过子类的方式来创建对象。

简单工厂模式相对较简单,适用于创建对象的逻辑较为固定;而工厂方法模式更加灵活,允许不同的子类决定创建哪种对象,使得系统更容易扩展和维护。

总的来说,简单工厂模式将对象的创建逻辑集中在一个工厂类中,对客户端来说更加简单;而工厂方法模式将对象的创建逻辑分散到不同的子类中,更符合开闭原则,使得系统更加灵活和可扩展。

以上内容由ChatGPT生成

总结

工厂方法模式的优点是,我们知道要一个具体的对象,也知道这个对象的类。但是不用关心谁创建了它,创建的过程如何。

在上述日志框架中的应用可以看出,多个工厂其实是冲突的。在实际使用时我们只用一个即可。但是这并不是方法工厂模式的要求,方法工厂模式并没有要求多个工厂不能共存,需要结合实际的应用场景来灵活设计、灵活使用。切勿生搬硬套!

工厂方法模式(Factory Method Pattern)

http://jaune162.blog/design-pattern/factory-method-pattern.html

作者

大扑棱蛾子(jaune162@126.com)

发布于

2024-02-05

更新于

2024-09-11

许可协议

评论