设计模式(三):工厂方法模式

Published on 2024-02-29 17:10 in 分类: 博客 with 狂盗一枝梅
分类: 博客

在上一篇文章《设计模式(2):简单工厂模式》中,以文件解析为例,解释了简单工厂模式的用法,简单工厂模式确实简单,但是它有以下几个问题:

1、不符合开闭原则:当需要添加新的产品类型时,必须修改工厂类的代码,违背了开闭原则。这种修改可能会影响工厂类的稳定性和可维护性。

2、工厂类职责过重,有可能违反单一职责原则:在简单工厂模式中,工厂类负责创建不同的产品对象,随着产品类型的增加,工厂类的职责会变得越来越重,代码复杂度逐渐增加。

一、工厂方法模式的定义

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它提供了一种通过定义工厂方法来创建对象的方式,而不是直接在客户端代码中使用new关键字实例化对象。工厂方法模式通过将对象的创建委托给具体的工厂类来解耦客户端代码和具体对象的创建过程。只是看定义似乎和简单工厂模式差不多,但是它和简单工厂模式有区别:

  1. 作用范围和职责:
    • 简单工厂模式:由一个工厂类负责创建所有产品对象,根据客户端传入的参数或条件来创建不同的产品对象。工厂类承担了对象创建的全部职责。
    • 工厂方法模式:通过定义一个抽象工厂接口和多个具体工厂类,每个具体工厂类负责创建特定类型的产品对象。每个具体工厂类只负责创建特定的产品对象,工厂类的职责更加明确和单一。
  2. 扩展性和灵活性:
    • 简单工厂模式:如果需要添加新的产品类型,需要修改工厂类的代码,违背了开闭原则。工厂类聚集了所有产品的创建逻辑,扩展性较差。
    • 工厂方法模式:每个具体工厂类负责创建特定类型的产品对象,当需要添加新的产品类型时,只需添加相应的具体工厂类即可,不需要修改现有的代码。扩展性更好,符合开闭原则。
  3. 对象创建的灵活性:
    • 简单工厂模式:创建对象的逻辑是静态的,无法在运行时动态地改变创建行为。
    • 工厂方法模式:每个具体工厂类都有自己的工厂方法,可以在运行时根据需要选择具体的工厂类,从而改变对象的创建行为。
  4. 适用场景:
    • 简单工厂模式适用于简单的对象创建场景,只有一个工厂类负责创建所有产品对象,适用于产品类型较少且不经常发生变化的情况。
    • 工厂方法模式适用于复杂的对象创建场景,每个具体工厂类负责创建特定类型的产品对象,适用于需要支持多个产品类型或产品等级结构的情况。

可以说,工厂方法模式是简单工厂模式的升级版

二、案例

我们将上一个在简单工厂模式中的案例改造成工厂方法模式。

1、回顾简单工厂模式

首先,先回忆下之前简单工厂模式

简单工厂模式.drawio FileParserFactory承担了所有的FileParser的创建

public class FileParserFactory {
    public FileParser createFileParser(String fileType) {
        if (fileType.equalsIgnoreCase("xml")) {
            return new XmlFileParser();
        } else if (fileType.equalsIgnoreCase("csv")) {
            return new CsvFileParser();
        } else if (fileType.equalsIgnoreCase("json")) {
            return new JsonFileParser();
        }
        return null;
    }
}

现在改造下,每个Parser都有自己的单独的工厂类创建

2、改造为工厂方法模式

类图如下 工厂方法模式类图

我们需要定义一个抽象的文件解析器工厂接口(FileParserFactory),该接口声明了创建文件解析器的方法:

public interface FileParserFactory {
    FileParser createFileParser();
}

然后,我们可以为每种文件类型实现具体的文件解析器工厂类,例如XML文件解析器工厂(XmlFileParserFactory)、CSV文件解析器工厂(CsvFileParserFactory)和JSON文件解析器工厂(JsonFileParserFactory)。这些工厂类分别实现了FileParserFactory接口,并负责创建对应的文件解析器对象:

public class XmlFileParserFactory implements FileParserFactory {
    @Override
    public FileParser createFileParser() {
        return new XmlFileParser();
    }
}

public class CsvFileParserFactory implements FileParserFactory {
    @Override
    public FileParser createFileParser() {
        return new CsvFileParser();
    }
}

public class JsonFileParserFactory implements FileParserFactory {
    @Override
    public FileParser createFileParser() {
        return new JsonFileParser();
    }
}

接下来,我们可以定义具体的文件解析器类,如之前的XML文件解析器(XmlFileParser)、CSV文件解析器(CsvFileParser)和JSON文件解析器(JsonFileParser)。

public class XmlFileParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析XML文件: " + filePath);
        // 具体的解析逻辑
    }
}

public class CsvFileParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析CSV文件: " + filePath);
        // 具体的解析逻辑
    }
}

public class JsonFileParser implements FileParser {
    @Override
    public void parse(String filePath) {
        System.out.println("解析JSON文件: " + filePath);
        // 具体的解析逻辑
    }
}

最后,我们可以使用相应的文件解析器工厂来创建文件解析器对象,并进行文件解析操作:

public class Main {
    public static void main(String[] args) {
        FileParserFactory xmlFactory = new XmlFileParserFactory();
        FileParser xmlParser = xmlFactory.createFileParser();
        xmlParser.parse("data.xml"); // 解析XML文件: data.xml

        FileParserFactory csvFactory = new CsvFileParserFactory();
        FileParser csvParser = csvFactory.createFileParser();
        csvParser.parse("data.csv"); // 解析CSV文件: data.csv

        FileParserFactory jsonFactory = new JsonFileParserFactory();
        FileParser jsonParser = jsonFactory.createFileParser();
        jsonParser.parse("data.json"); // 解析JSON文件: data.json
    }
}

三、总结

工厂方法模式比起简单工厂模式,只是将工厂类做了更改,将原来单一的工厂类拆分成一个抽象类以及若干个具体工厂类,这是从升级的角度上来看;从另一方面来看,如果业务比较简单,有些情况下可以将多工厂的工厂方法模式“缩小”为单工厂的简单方法模式。


#设计模式
目录