一文带你玩转——Java设计模式:工厂模式详解

926 阅读7分钟

工厂模式(Factory Pattern)是一种创建型设计模式,它的核心思想是将对象的创建过程抽象出来,提供一个用于创建对象的接口或方法,而不直接暴露对象的创建细节。这样不仅提高了代码的可扩展性和灵活性,还遵循了开闭原则,即对扩展开放、对修改关闭。

本文将从工厂模式的原理、背景、应用场景以及实际Demo等多个角度来详细介绍工厂模式。

一、工厂模式的原理

工厂模式的主要目标是将对象的创建逻辑从业务代码中抽象出来,减少代码的耦合度。在工厂模式中,核心是提供一个工厂类,该类根据不同的条件来决定创建哪种具体的对象。根据实现方式的不同,工厂模式又可以分为以下几类:

  • 简单工厂模式(Simple Factory)
  • 工厂方法模式(Factory Method)
  • 抽象工厂模式(Abstract Factory)

二、工厂模式的背景

在面向对象编程中,创建对象的过程往往不简单,可能涉及很多逻辑判断。如果将对象的创建代码散布在应用的各个地方,不仅不利于维护,而且会导致代码耦合严重。一旦对象的创建逻辑发生变化,可能需要修改大量的代码,这与开闭原则相违背。

为了解决这个问题,工厂模式应运而生。通过引入一个专门的工厂类来创建对象,可以将对象的创建逻辑封装起来,业务代码不再关心对象的创建细节,从而提高代码的可维护性和可扩展性。

三、工厂模式的应用场景

工厂模式适用于以下几种场景:

  1. 对象的创建过程较复杂:例如,创建对象时需要依赖多个参数或者涉及复杂的逻辑判断。
  2. 需要为不同的场景提供不同的对象:例如,日志系统中可以根据不同的日志级别创建不同的日志记录对象。
  3. 需要通过配置或输入条件来动态决定创建哪种类型的对象:例如,根据不同的数据库配置创建不同的数据库连接对象。

四、工厂模式的分类及实现

1. 简单工厂模式(Simple Factory)

简单工厂模式是一种最基本的工厂模式,工厂类根据传入的参数创建不同的对象。

java
复制代码
// 产品接口
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 简单工厂类
class SimpleFactory {
    public static Product createProduct(String type) {
        if ("A".equals(type)) {
            return new ConcreteProductA();
        } else if ("B".equals(type)) {
            return new ConcreteProductB();
        } else {
            throw new IllegalArgumentException("未知的产品类型");
        }
    }
}

使用示例:

java
复制代码
public class Main {
    public static void main(String[] args) {
        Product productA = SimpleFactory.createProduct("A");
        productA.use(); // 输出 "使用产品A"
        
        Product productB = SimpleFactory.createProduct("B");
        productB.use(); // 输出 "使用产品B"
    }
}

优点:

  • 简单易实现,适合创建逻辑简单的对象。

缺点:

  • 当产品种类较多时,工厂类会变得臃肿,不符合开闭原则(每增加一个产品类型都需要修改工厂类)。

2. 工厂方法模式(Factory Method)

工厂方法模式通过定义一个创建对象的接口,让子类来决定实例化哪一个具体类。这样,工厂方法将对象的创建推迟到子类中去完成,符合开放封闭原则

java
复制代码
// 产品接口
interface Product {
    void use();
}

// 具体产品A
class ConcreteProductA implements Product {
    @Override
    public void use() {
        System.out.println("使用产品A");
    }
}

// 具体产品B
class ConcreteProductB implements Product {
    @Override
    public void use() {
        System.out.println("使用产品B");
    }
}

// 抽象工厂
interface ProductFactory {
    Product createProduct();
}

// 具体工厂A
class ProductAFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new ConcreteProductA();
    }
}

// 具体工厂B
class ProductBFactory implements ProductFactory {
    @Override
    public Product createProduct() {
        return new ConcreteProductB();
    }
}

使用示例:

java
复制代码
public class Main {
    public static void main(String[] args) {
        ProductFactory factoryA = new ProductAFactory();
        Product productA = factoryA.createProduct();
        productA.use(); // 输出 "使用产品A"
        
        ProductFactory factoryB = new ProductBFactory();
        Product productB = factoryB.createProduct();
        productB.use(); // 输出 "使用产品B"
    }
}

优点:

  • 每个具体产品都有自己独立的工厂,符合单一职责原则,且扩展性强。

缺点:

  • 当需要增加新的产品时,必须新建对应的工厂类,导致类数量增加。

3. 抽象工厂模式(Abstract Factory)

抽象工厂模式是工厂模式的进一步抽象,它不仅可以创建一个产品,还可以创建一组相关的产品。通过将多个产品抽象在一起,抽象工厂模式可以为不同的产品族提供创建方法。

java
复制代码
// 产品族中的产品A接口
interface ProductA {
    void use();
}

// 产品族中的产品B接口
interface ProductB {
    void use();
}

// 具体产品A1
class ConcreteProductA1 implements ProductA {
    @Override
    public void use() {
        System.out.println("使用产品A1");
    }
}

// 具体产品A2
class ConcreteProductA2 implements ProductA {
    @Override
    public void use() {
        System.out.println("使用产品A2");
    }
}

// 具体产品B1
class ConcreteProductB1 implements ProductB {
    @Override
    public void use() {
        System.out.println("使用产品B1");
    }
}

// 具体产品B2
class ConcreteProductB2 implements ProductB {
    @Override
    public void use() {
        System.out.println("使用产品B2");
    }
}

// 抽象工厂,定义创建一组相关产品的方法
interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

// 具体工厂1,生产A1和B1
class ConcreteFactory1 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA1();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB1();
    }
}

// 具体工厂2,生产A2和B2
class ConcreteFactory2 implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA2();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB2();
    }
}

使用示例:

java
复制代码
public class Main {
    public static void main(String[] args) {
        AbstractFactory factory1 = new ConcreteFactory1();
        ProductA productA1 = factory1.createProductA();
        ProductB productB1 = factory1.createProductB();
        productA1.use(); // 输出 "使用产品A1"
        productB1.use(); // 输出 "使用产品B1"
        
        AbstractFactory factory2 = new ConcreteFactory2();
        ProductA productA2 = factory2.createProductA();
        ProductB productB2 = factory2.createProductB();
        productA2.use(); // 输出 "使用产品A2"
        productB2.use(); // 输出 "使用产品B2"
    }
}

优点:

  • 可以创建一组相关的产品,适合产品族的扩展。
  • 符合开闭原则,增加新产品族只需新增工厂类,不需要修改已有代码。

缺点:

  • 增加新的产品族时需要修改所有的工厂类,不符合单一职责原则。

五、工厂模式的实际应用Demo

以一个日志系统为例,不同场景下可能需要将日志输出到不同的地方,例如控制台文件数据库。使用工厂模式可以根据配置或环境选择相应的日志记录器。

java
复制代码
// 日志记录器接口
interface Logger {
    void log(String message);
}

// 控制台日志记录器
class ConsoleLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("控制台日志: " + message);
    }
}

// 文件日志记录器
class FileLogger implements Logger {
    @Override
    public void log(String message

4o

您说:

继续

ChatGPT 说:

ChatGPT

java
复制代码
    ) {
        System.out.println("文件日志: " + message);
        // 这里可以添加将日志写入文件的逻辑
    }
}

// 数据库日志记录器
class DatabaseLogger implements Logger {
    @Override
    public void log(String message) {
        System.out.println("数据库日志: " + message);
        // 这里可以添加将日志写入数据库的逻辑
    }
}

// 抽象工厂,定义创建日志记录器的方法
interface LoggerFactory {
    Logger createLogger();
}

// 控制台日志工厂
class ConsoleLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        return new ConsoleLogger();
    }
}

// 文件日志工厂
class FileLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        return new FileLogger();
    }
}

// 数据库日志工厂
class DatabaseLoggerFactory implements LoggerFactory {
    @Override
    public Logger createLogger() {
        return new DatabaseLogger();
    }
}

// 日志管理器,使用工厂类来创建日志记录器
class LoggerManager {
    private Logger logger;

    public LoggerManager(LoggerFactory factory) {
        this.logger = factory.createLogger();
    }

    public void log(String message) {
        logger.log(message);
    }
}

使用示例

在实际应用中,可以根据需要选择不同的日志记录器:

java
复制代码
public class Main {
    public static void main(String[] args) {
        // 使用控制台日志记录器
        LoggerFactory consoleFactory = new ConsoleLoggerFactory();
        LoggerManager consoleLoggerManager = new LoggerManager(consoleFactory);
        consoleLoggerManager.log("这是一个控制台日志。"); // 输出 "控制台日志: 这是一个控制台日志。"

        // 使用文件日志记录器
        LoggerFactory fileFactory = new FileLoggerFactory();
        LoggerManager fileLoggerManager = new LoggerManager(fileFactory);
        fileLoggerManager.log("这是一个文件日志。"); // 输出 "文件日志: 这是一个文件日志。"

        // 使用数据库日志记录器
        LoggerFactory dbFactory = new DatabaseLoggerFactory();
        LoggerManager dbLoggerManager = new LoggerManager(dbFactory);
        dbLoggerManager.log("这是一个数据库日志。"); // 输出 "数据库日志: 这是一个数据库日志。"
    }
}

总结

工厂模式是一个非常实用的设计模式,能够有效地管理对象的创建过程,减少代码耦合,提高代码的可扩展性和可维护性。通过将对象的创建逻辑集中在工厂类中,工厂模式使得应用代码能够专注于业务逻辑,而不必关心具体的对象创建细节。在实际开发中,灵活运用工厂模式,可以使系统的架构更加清晰、易于维护。