通俗易懂设计模式(工厂方法模式)

75 阅读5分钟

工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但允许子类决定实例化哪个类。工厂方法让类的实例化推迟到子类。

工厂方法模式的优点:

  1. 解耦:将对象的创建和使用分离,降低了系统的耦合度。
  2. 扩展性:增加新的产品类时,只需创建新的工厂子类,不需要修改已有代码。
  3. 可维护性:工厂方法模式使得代码更易于维护,因为产品类的创建逻辑被封装在工厂子类中。

工厂方法模式的缺点:

  1. 增加类的数量:由于需要为每个产品类创建一个工厂子类,因此类的数量会增加。
  2. 增加系统的复杂度:工厂方法模式增加了系统的复杂度,需要更多的代码来实现。

Java 实现工厂方法模式的示例代码:

// 抽象产品类
public interface Product {
    void show();
}

// 具体产品类A
public class ProductA implements Product {
    @Override
    public void show() {
        System.out.println("Product A");
    }
}

// 具体产品类B
public class ProductB implements Product {
    @Override
    public void show() {
        System.out.println("Product B");
    }
}

// 抽象工厂类
public interface Factory {
    Product createProduct();
}

// 具体工厂类A
public class FactoryA implements Factory {
    @Override
    public Product createProduct() {
        return new ProductA();
    }
}

// 具体工厂类B
public class FactoryB implements Factory {
    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

// 客户端代码
public class Client {
    public static void main(String[] args) {
        Factory factory = new FactoryA();
        Product product = factory.createProduct();
        product.show();
    }
}

在这个示例中,我们定义了一个抽象产品类 Product 和两个具体产品类 ProductAProductB。接着,我们定义了一个抽象工厂类 Factory 和两个具体工厂类 FactoryAFactoryB。每个具体工厂类实现了 createProduct() 方法,用于创建对应的产品实例。

在客户端代码中,我们创建了一个具体工厂类 FactoryA 的实例,并通过调用 createProduct() 方法创建了一个 ProductA 的实例。然后,我们调用 show() 方法显示产品信息。

使用工厂方法模式时,需要注意以下几点:

  1. 工厂方法模式适用于产品类的创建逻辑较为复杂的场景,可以将创建逻辑封装在工厂子类中,提高代码的可维护性。
  2. 工厂方法模式需要为每个产品类创建一个工厂子类,因此类的数量会增加。在产品类较多的情况下,需要考虑减少类的数量,可以使用其他创建型设计模式,如简单工厂模式(Simple Factory Pattern)或工厂模式(Factory Pattern)。

场景举例

场景一:多数据库支持

在一个应用程序中,可能需要支持多种数据库,如MySQL、Oracle、SQL Server等。为了实现多数据库的支持,我们可以使用工厂方法模式来根据配置文件或命令行参数动态地选择数据库连接。

使用工厂方法模式来实现多数据库支持,可以让代码更加简洁、易于维护。具体实现如下:

// 数据库连接接口
interface DatabaseConnection {
    void connect();
}

// MySQL连接实现
class MySQLConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connected to MySQL");
    }
}

// Oracle连接实现
class OracleConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connected to Oracle");
    }
}

// SQL Server连接实现
class SQLServerConnection implements DatabaseConnection {
    @Override
    public void connect() {
        System.out.println("Connected to SQL Server");
    }
}

// 数据库连接工厂接口
interface DatabaseConnectionFactory {
    DatabaseConnection createConnection();
}

// MySQL连接工厂实现
class MySQLConnectionFactory implements DatabaseConnectionFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new MySQLConnection();
    }
}

// Oracle连接工厂实现
class OracleConnectionFactory implements DatabaseConnectionFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new OracleConnection();
    }
}

// SQL Server连接工厂实现
class SQLServerConnectionFactory implements DatabaseConnectionFactory {
    @Override
    public DatabaseConnection createConnection() {
        return new SQLServerConnection();
    }
}

// 数据库连接管理器
class DatabaseConnectionManager {
    private DatabaseConnectionFactory factory;

    public DatabaseConnectionManager(DatabaseConnectionFactory factory) {
        this.factory = factory;
    }

    public void connect() {
        DatabaseConnection connection = factory.createConnection();
        connection.connect();
    }
}

// 测试类
public class FactoryMethodPatternDemo {
    public static void main(String[] args) {
        String databaseType = "MySQL"; // 从配置文件或命令行参数获取

        DatabaseConnectionManager manager;
        switch (databaseType) {
            case "MySQL":
                manager = new DatabaseConnectionManager(new MySQLConnectionFactory());
                break;
            case "Oracle":
                manager = new DatabaseConnectionManager(new OracleConnectionFactory());
                break;
            case "SQLServer":
                manager = new DatabaseConnectionManager(new SQLServerConnectionFactory());
                break;
            default:
                throw new IllegalArgumentException("Invalid database type");
        }

        manager.connect();
    }
}

场景二:多文件格式支持

在一个应用程序中,可能需要支持多种文件格式,如CSV、JSON、XML等。为了实现多文件格式的支持,我们可以使用工厂方法模式来根据文件扩展名动态地选择文件解析器。

使用工厂方法模式来实现多文件格式支持,可以让代码更加简洁、易于维护。具体实现如下:

// 文件解析器接口
interface FileParser {
    void parse(File file);
}

// CSV文件解析器实现
class CSVParser implements FileParser {
    @Override
    public void parse(File file) {
        System.out.println("Parsing CSV file: " + file.getName());
    }
}

// JSON文件解析器实现
class JSONParser implements FileParser {
    @Override
    public void parse(File file) {
        System.out.println("Parsing JSON file: " + file.getName());
    }
}

// XML文件解析器实现
class XMLParser implements FileParser {
    @Override
    public void parse(File file) {
        System.out.println("Parsing XML file: " + file.getName());
    }
}

// 文件解析器工厂接口
interface FileParserFactory {
    FileParser createParser(String extension);
}

// CSV文件解析器工厂实现
class CSVParserFactory implements FileParserFactory {
    @Override
    public FileParser createParser(String extension) {
        return new CSVParser();
    }
}

// JSON文件解析器工厂实现
class JSONParserFactory implements FileParserFactory {
    @Override
    public FileParser createParser(String extension) {
        return new JSONParser();
    }
}

// XML文件解析器工厂实现
class XMLParserFactory implements FileParserFactory {
    @Override
    public FileParser createParser(String extension) {
        return new XMLParser();
    }
}

// 文件解析管理器
class FileParserManager {
    private FileParserFactory factory;

    public FileParserManager(FileParserFactory factory) {
        this.factory = factory;
    }

    public void parse(File file) {
        String extension = FilenameUtils.getExtension(file.getName());
        FileParser parser = factory.createParser(extension);
        parser.parse(file);
    }
}

// 测试类
public class FactoryMethodPatternDemo {
    public static void main(String[] args) {
        File file = new File("example.csv"); // 要解析的文件

        FileParserManager manager;
        switch (FilenameUtils.getExtension(file.getName())) {
            case "csv":
                manager = new FileParserManager(new CSVParserFactory());
                break;
            case "json":
                manager = new FileParserManager(new JSONParserFactory());
                break;
            case "xml":
                manager = new FileParserManager(new XMLParserFactory());
                break;
            default:
                throw new IllegalArgumentException("Invalid file format");
        }

        manager.parse(file);
    }
}

在这两个场景中,我们都使用了工厂方法模式来根据不同的条件动态地选择具体的实现类。在第一个场景中,我们使用工厂方法模式来实现多数据库支持;在第二个场景中,我们使用工厂方法模式来实现多文件格式支持。通过使用工厂方法模式,我们可以让代码更加简洁、易于维护,同时提高了代码的可扩展性和可重用性。