1. 意图(Intent)

定义了一个创建对象的接口,但由子类决定要实例化哪个类。工厂方法把实例化操作推迟到子类。

简单工厂模式很简单,如果它能满足我们的需要,我觉得就不要折腾了。之所以需要引入工厂模式,是因为我们往往需要使用两个或两个以上的工厂,我们无法确定使用那个工厂,因此需要把实例化操作延迟到子类。

2. 类图(Class Diagram)

在简单工厂中,创建对象的是另一个类,而在工厂方法中,是由子类来创建对象。

下图中,Factory 有一个 doSomething() 方法,这个方法需要用到一个产品对象,这个产品对象由 factoryMethod() 方法创建。该方法是抽象的,需要由子类去实现。
工厂模式(Factory Method) - 图1
工厂模式(Factory Method) - 图2

3. 实现(Implementation)

工厂模式: 把实例化操作推迟到子类 的例子 [ 继承 ]

  1. public abstract class Factory {
  2. abstract public Product factoryMethod();
  3. public void doSomething() {
  4. Product product = factoryMethod();
  5. // do something with the product
  6. }
  7. }
  1. public class ConcreteFactoryA extends Factory {
  2. public Product factoryMethod() {
  3. return new ConcreteProductA();
  4. }
  5. //当 ConcreteFactoryA 调用 doSomething 时 product会被初始化为ConcreteProductA
  6. }
  1. public class ConcreteFactoryB extends Factory {
  2. public Product factoryMethod() {
  3. return new ConcreteProductB();
  4. }
  5. }
  1. public class ConcreteFactoryC extends Factory {
  2. public Product factoryMethod() {
  3. return new ConcreteProductC();
  4. }
  5. }

客户端调用:

  1. public class Client {
  2. public static void main(String[] args) {
  3. Factory concreteProduct = new ConcreteFactoryA(); //第一步,明确工厂为A产品工厂
  4. concreteProduct.doSomething(); //对产品A执行某些操作
  5. }
  6. }

工厂模式:食物工厂 [ 接口实现 ]
image.png

  1. public interface FoodFactory {
  2. Food makeFood(String name);
  3. }
  1. public class ChineseFoodFactory implements FoodFactory {
  2. @Override
  3. public Food makeFood(String name) {
  4. if (name.equals("A")) {
  5. return new ChineseFoodA();
  6. } else if (name.equals("B")) {
  7. return new ChineseFoodB();
  8. } else {
  9. return null;
  10. }
  11. }
  12. }
  1. public class AmericanFoodFactory implements FoodFactory {
  2. @Override
  3. public Food makeFood(String name) {
  4. if (name.equals("A")) {
  5. return new AmericanFoodA();
  6. } else if (name.equals("B")) {
  7. return new AmericanFoodB();
  8. } else {
  9. return null;
  10. }
  11. }
  12. }

其中,ChineseFoodA、ChineseFoodB、AmericanFoodA、AmericanFoodB 都派生自 Food。
客户端调用:

  1. public class Client {
  2. public static void main(String[] args) {
  3. // 先选择一个具体的工厂
  4. FoodFactory factory = new ChineseFoodFactory();
  5. // 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
  6. Food food = factory.makeFood("A");
  7. }
  8. }

虽然都是调用 makeFood("A") 制作 A 类食物,但是,不同的工厂生产出来的完全不一样。
核心在于,我们需要在第一步选好我们需要的工厂

比如,我们有 LogFactory 接口,实现类有 FileLogFactory KafkaLogFactory,分别对应将日志写入文件和写入 Kafka 中,显然,我们客户端第一步就需要决定到底要实例化 FileLogFactory 还是 KafkaLogFactory,这将决定之后的所有的操作。

4. JDK