简单工厂模式 (Simple Factory Pattern) 在Spring Boot 中的应用

简单工厂模式(Simple Factory Pattern)虽然不属于 GoF 23 种经典设计模式,但在实际开发中非常常用,尤其是在 Spring Boot 项目中。它提供了一种简单的方式来创建对象,将对象的创建逻辑集中到一个工厂类中。

一、简单工厂模式的定义

简单工厂模式的核心思想是:

  1. 定义一个工厂类 (Factory Class): 这个工厂类负责创建所有产品对象。
  2. 工厂类包含一个静态方法 (Static Method): 这个静态方法根据传入的参数(通常是字符串类型或枚举类型),来决定创建哪种具体的产品对象。
  3. 客户端代码通过工厂类的静态方法获取产品对象: 客户端代码不需要直接使用 new 关键字创建对象,而是调用工厂类的静态方法,并传入相应的参数。

简单工厂模式的结构:

  • 工厂类 (Factory): 负责创建所有产品对象的类。
  • 抽象产品类/接口 (Product): 所有产品对象的共同父类或接口。
  • 具体产品类 (ConcreteProduct): 工厂类创建的具体对象类型。

二、简单工厂模式的优缺点

  • 优点:

    • 简单易用: 实现简单,代码量少,容易理解。
    • 封装创建逻辑: 将对象的创建逻辑集中到工厂类中,客户端代码无需关心对象的创建细节。
    • 降低耦合度: 客户端代码不直接依赖于具体的产品类,而是依赖于工厂类和抽象产品类/接口。
  • 缺点:

    • 违反开闭原则: 当需要添加新的产品类型时,需要修改工厂类的代码(例如,添加新的 if-else 分支或 case 分支),这违反了开闭原则(对扩展开放,对修改关闭)。
    • 工厂类职责过重: 工厂类负责创建所有产品对象,如果产品种类很多,工厂类的代码会变得很庞大,难以维护。
    • 可扩展性差: 由于违反开闭原则,简单工厂模式的可扩展性较差。

三、在 Spring Boot 中使用简单工厂模式

在 Spring Boot 中,你可以通过以下方式使用简单工厂模式:

  1. 直接使用静态方法:

    • 创建一个工厂类,并在其中定义一个静态方法,根据参数创建不同的对象。
    java 复制代码
    // 抽象产品接口
    interface Product {
        void doSomething();
    }
    
    // 具体产品 A
    class ConcreteProductA implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA");
        }
    }
    
    // 具体产品 B
    class ConcreteProductB implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB");
        }
    }
    
    // 简单工厂类
    public class SimpleFactory {
        public static Product createProduct(String type) {
            if ("A".equals(type)) {
                return new ConcreteProductA();
            } else if ("B".equals(type)) {
                return new ConcreteProductB();
            } else {
                return null; // 或者抛出异常
            }
        }
    }
    
    // 使用
    public class Client {
        public static void main(String[] args) {
            Product productA = SimpleFactory.createProduct("A");
            productA.doSomething();
    
            Product productB = SimpleFactory.createProduct("B");
            productB.doSomething();
        }
    }
  2. 结合 Spring 的 @Component@Autowired

    • 将工厂类注册为 Spring Bean(使用 @Component 注解)。
    • 在需要使用工厂的地方,通过 @Autowired 注入工厂 Bean。
    • 这种方式可以更好地利用 Spring 的依赖注入功能。
    java 复制代码
    import org.springframework.stereotype.Component;
    
    // ... (Product 接口和 ConcreteProductA, ConcreteProductB 类保持不变) ...
    
    // 简单工厂类,使用 @Component 注册为 Spring Bean
    @Component
    public class SimpleFactory {
        public Product createProduct(String type) { // 不需要是静态方法了
            if ("A".equals(type)) {
                return new ConcreteProductA();
            } else if ("B".equals(type)) {
                return new ConcreteProductB();
            } else {
                return null;
            }
        }
    }
    
    // 使用
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    @Service
    public class Client {
    
        @Autowired
        private SimpleFactory simpleFactory; // 注入 SimpleFactory
    
        public void run() {
            Product productA = simpleFactory.createProduct("A");
            productA.doSomething();
    
            Product productB = simpleFactory.createProduct("B");
            productB.doSomething();
        }
    }
  3. 使用枚举 (Enum) 实现单例的简单工厂:

    • 如果你的产品对象是无状态的, 并且每种类型只需要一个实例,可以使用枚举来实现简单工厂,同时保证单例。
    java 复制代码
    interface Product {
        void doSomething();
    }
    
    // 具体产品 A
    class ConcreteProductA implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductA");
        }
    }
    
    // 具体产品 B
    class ConcreteProductB implements Product {
        @Override
        public void doSomething() {
            System.out.println("ConcreteProductB");
        }
    }
    // 使用枚举实现简单工厂
    enum ProductFactory {
      INSTANCE;
    
      public Product createProduct(String type) {
        if ("A".equals(type)) {
          return new ConcreteProductA();
        } else if ("B".equals(type)) {
          return new ConcreteProductB();
        } else {
          return null;
        }
      }
    }
    //使用
    Product product = ProductFactory.INSTANCE.createProduct("A");
  4. 结合@Configuration@Bean:

    • 你可以使用 @Configuration@Bean 注解来定义工厂方法,并将工厂方法创建的对象注册为 Spring Bean。 这种方式更符合 Spring 的配置风格。

      java 复制代码
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      
      // ... (Product 接口和 ConcreteProductA, ConcreteProductB 类保持不变) ...
      
      @Configuration
      public class AppConfig {
      
          @Bean
          public Product productA() { // 工厂方法,创建 ConcreteProductA
              return new ConcreteProductA();
          }
      
          @Bean
          public Product productB() { // 工厂方法,创建 ConcreteProductB
              return new ConcreteProductB();
          }
      
          // 你也可以定义一个更通用的工厂方法,根据参数创建不同的 Bean
          @Bean
          public Product product(@Value("${product.type}") String productType) {
                if("A".equals(productType)){
                    return new ConcreteProductA();
                } else {
                    return new ConcreteProductB();
                }
          }
      }

四、使用场景

简单工厂模式适用于以下场景:

  1. 创建对象种类较少: 如果需要创建的对象种类不多,并且创建逻辑比较简单,可以使用简单工厂模式。
  2. 客户端不需要关心对象的创建细节: 客户端只需要知道如何通过工厂类获取对象即可。
  3. 对象创建逻辑相对稳定: 如果对象的创建逻辑不经常变化,可以使用简单工厂模式。

五、与 Spring Boot 特性的结合

  • @Component@Autowired 将工厂类注册为 Spring Bean,方便依赖注入。
  • @Configuration@Bean 使用 @Bean 注解定义工厂方法,将工厂方法创建的对象注册为 Spring Bean。
  • @Value 可以使用 @Value 注解从配置文件中读取参数,传递给工厂方法,实现更灵活的对象创建。
  • @Conditional 可以使用 @Conditional 注解(例如 @ConditionalOnProperty@ConditionalOnClass 等)来根据条件决定是否创建某个 Bean,实现更灵活的工厂配置。

六. 简单工厂模式退化为简单工具类

如果简单工厂模式中,工厂类只负责创建对象,没有任何其他的业务逻辑,那么这个工厂类实际上就退化成了一个简单的工具类。在这种情况下,是否使用工厂模式就看个人喜好了,因为并没有带来特别大的好处,也没有明显的坏处。

总结

简单工厂模式是一种简单易用的创建型设计模式,它可以封装对象的创建逻辑,降低代码耦合度。 在 Spring Boot 中,你可以通过多种方式使用简单工厂模式,并结合 Spring 的特性来实现更灵活、更可维护的对象创建。 但是,需要注意简单工厂模式违反开闭原则的缺点,如果需要频繁添加新的产品类型,可以考虑使用工厂方法模式或抽象工厂模式。

相关推荐
努力的小郑33 分钟前
MySQL索引(三):字符串索引优化之前缀索引
后端·mysql·性能优化
IT_陈寒1 小时前
🔥3分钟掌握JavaScript性能优化:从V8引擎原理到5个实战提速技巧
前端·人工智能·后端
程序员清风1 小时前
贝壳一面:年轻代回收频率太高,如何定位?
java·后端·面试
考虑考虑2 小时前
Java实现字节转bcd编码
java·后端·java ee
AAA修煤气灶刘哥2 小时前
ES 聚合爽到飞起!从分桶到 Java 实操,再也不用翻烂文档
后端·elasticsearch·面试
爱读源码的大都督2 小时前
Java已死?别慌,看我如何用Java手写一个Qwen Code Agent,拯救Java
java·人工智能·后端
勇往直前plus3 小时前
Sentinel微服务保护
java·spring boot·微服务·sentinel
星辰大海的精灵3 小时前
SpringBoot与Quartz整合,实现订单自动取消功能
java·后端·算法
天天摸鱼的java工程师3 小时前
RestTemplate 如何优化连接池?—— 八年 Java 开发的踩坑与优化指南
java·后端
一乐小哥3 小时前
一口气同步10年豆瓣记录———豆瓣书影音同步 Notion分享 🚀
后端·python