欢迎光临
我们一直在努力

Java设计模式实战:工厂模式,从“Hello World”到企业级架构的正确打开方式

目录

一、为什么我们需要工厂模式?

二、核心套路一:简单工厂 (Simple Factory)

1. 定义与结构

2. Java代码实战

3. 优缺点分析

三、核心套路二:工厂方法 (Factory Method)

1. 定义与结构

2. Java代码实战

3. 优缺点分析

四、灵魂拷问:实际开发中到底用哪个?

1. 简单工厂 vs 工厂方法:选择指南

2. 现代 Java 开发的“第三条路”:Spring 依赖注入 (DI)

五、避坑指南与最佳实践

六、总结


摘要:工厂模式是Java开发中最经典、使用频率最高的创建型设计模式之一。很多初学者容易陷入“为了模式而模式”的误区,导致代码过度设计。本文将通过清晰的Java代码示例,深入浅出地讲解简单工厂与工厂方法的核心区别,并结合Spring生态下的最佳实践,告诉你到底该在什么场景下用哪种工厂,助你写出既优雅又实用的代码。

一、为什么我们需要工厂模式?

在传统的面向对象编程中,我们习惯直接使用 new 关键字来创建对象:

// 传统方式
Car myCar = new BenzCar();
myCar.drive();

这种方式虽然简单直接,但随着系统复杂度的提升,弊端逐渐显现:

  • 耦合度高:调用者依赖具体类(BenzCar),一旦类名变更或构造逻辑变化,所有 new 的地方都要修改。
  • 违反开闭原则:如果要增加新产品(如 TeslaCar),必须修改原有业务逻辑。
  • 创建逻辑分散:如果对象创建需要复杂的校验、配置或日志记录,这些逻辑会散落在各个业务代码中,难以维护。
  • 工厂模式的核心思想就是:将对象的创建逻辑封装起来,让调用者只关心“用什么”,而不关心“怎么造”。

    这就好比去餐厅点餐,你只需要告诉服务员“我要一份牛排”,至于牛排是哪个厨师做的、怎么切的、怎么煎的,你不需要知道,服务员(工厂)会直接把做好的牛排(对象)端给你。


    二、核心套路一:简单工厂 (Simple Factory)

    1. 定义与结构

    简单工厂(也称为静态工厂方法)是最基础的工厂模式。它创建一个专门的工厂类,根据传入的参数(如字符串、枚举)决定创建哪一种产品类的实例(看一遍就懂,很好理解)。

    2. Java代码实战

    假设我们要开发一个图形绘制模块,支持圆形和方形。

    // 1. 定义产品接口
    interface Shape {
    void draw();
    }

    // 2. 具体产品实现
    class Circle implements Shape {
    @Override
    public void draw() {
    System.out.println("画了一个圆形 ⭕");
    }
    }

    class Square implements Shape {
    @Override
    public void draw() {
    System.out.println("画了一个方形 ⬜");
    }
    }

    // 3. 简单工厂类
    class ShapeFactory {
    // 使用静态方法,无需实例化工厂即可调用
    public static Shape createShape(String type) {
    if ("circle".equalsIgnoreCase(type)) {
    return new Circle();
    } else if ("square".equalsIgnoreCase(type)) {
    return new Square();
    } else {
    throw new IllegalArgumentException("未知的形状类型: " + type);
    }
    }
    }

    // 4. 客户端调用
    public class SimpleFactoryDemo {
    public static void main(String[] args) {
    // 客户端只依赖接口 Shape 和工厂类,不依赖具体实现类
    Shape s1 = ShapeFactory.createShape("circle");
    s1.draw();

    Shape s2 = ShapeFactory.createShape("square");
    s2.draw();
    }
    }

    3. 优缺点分析

    • 优点:
      • 结构简单,易于理解。
      • 客户端免除了直接创建产品的责任,实现了责任分离。
    • 缺点:
      • 违反开闭原则:如果要增加一个 Triangle(三角形),必须修改 ShapeFactory 中的 if-else 逻辑。在大型系统中,这可能导致工厂类变得臃肿且难以维护。

    三、核心套路二:工厂方法 (Factory Method)

    1. 定义与结构

    工厂方法模式定义了一个创建对象的接口(抽象工厂),但让实现这个接口的子类来决定实例化哪一个类。工厂方法让类的实例化推迟到子类。

    2. Java代码实战

    假设我们要构建一个物流系统,支持陆运(卡车)和海运(轮船),且未来可能扩展空运。

    // 1. 定义产品接口
    interface Transport {
    void deliver();
    }

    // 2. 具体产品实现
    class Truck implements Transport {
    @Override
    public void deliver() {
    System.out.println("🚛 卡车通过公路运输货物");
    }
    }

    class Ship implements Transport {
    @Override
    public void deliver() {
    System.out.println("🚢 轮船通过海运运输货物");
    }
    }

    // 3. 抽象工厂 (Creator)
    // 这里定义了业务逻辑框架,但把具体的创建过程留给子类
    abstract class Logistics {
    // 工厂方法:由子类实现
    public abstract Transport createTransport();

    // 模板方法:包含通用业务逻辑
    public void planDelivery() {
    Transport transport = createTransport(); // 调用工厂方法
    System.out.print("物流计划启动:");
    transport.deliver();
    }
    }

    // 4. 具体工厂实现
    class RoadLogistics extends Logistics {
    @Override
    public Transport createTransport() {
    return new Truck();
    }
    }

    class SeaLogistics extends Logistics {
    @Override
    public Transport createTransport() {
    return new Ship();
    }
    }

    // 5. 客户端调用
    public class FactoryMethodDemo {
    public static void main(String[] args) {
    // 多态:父类引用指向子类对象
    Logistics roadLogistics = new RoadLogistics();
    roadLogistics.planDelivery();

    Logistics seaLogistics = new SeaLogistics();
    seaLogistics.planDelivery();

    // 【扩展性体现】:如果需要空运,只需新增 AirLogistics 和 Airplane 类,
    // 现有的 Logistics, RoadLogistics, SeaLogistics 代码一行都不用改!
    }
    }

    3. 优缺点分析

    • 优点:
      • 符合开闭原则:增加新产品时,只需新增对应的具体工厂和产品类,无需修改现有代码。
      • 解耦彻底:高层模块只依赖抽象工厂和抽象产品。
    • 缺点:
      • 类个数膨胀:每增加一个产品,就需要增加一个产品类和一个工厂类,系统复杂度增加。
      • 抽象性增加:增加了系统的理解难度。

    四、灵魂拷问:实际开发中到底用哪个?

    这是很多开发者最纠结的问题。答案并非非黑即白,而是取决于场景。

    1. 简单工厂 vs 工厂方法:选择指南

    维度简单工厂 (Simple Factory)工厂方法 (Factory Method)
    使用频率 ⭐⭐⭐⭐ (高频) ⭐⭐ (中低频,多用于框架底层)
    代码复杂度 高 (类数量多)
    扩展性 一般 (需修改代码) 极好 (无需修改代码)
    适用场景 工具类、策略选择、小型模块、产品类型固定 框架设计、插件系统、SDK、产品类型频繁变动

    结论:

    • 日常业务开发:90% 的场景下,简单工厂(或其变种“静态工厂方法”)完全够用。因为业务类型通常相对固定,为了扩展性牺牲代码简洁度是不划算的。
    • 框架/库开发:如果你是在写一个供他人扩展的框架(如 JDBC 驱动、日志框架),工厂方法是标准答案,因为它能完美支持第三方插件的无缝接入。

    2. 现代 Java 开发的“第三条路”:Spring 依赖注入 (DI)

    在 Spring Boot 统治的企业级开发中,我们其实很少手动写这两种工厂了。

    为什么? 因为 Spring 容器 已经帮你实现了终极版的“抽象工厂 + 简单工厂”。

    • 以前(手动工厂):

      // 痛苦地写 if-else 或者继承
      Service s = Factory.getService("mysql");

    • 现在(Spring DI):

      @Autowired
      private PaymentService paymentService; // Spring 自动帮你 new 好了

      // 或者通过构造函数注入
      public OrderController(PaymentService paymentService) {
      this.paymentService = paymentService;
      }

    在 Spring 中,你只需要定义接口和实现类,加上 @Component 或 @Bean 注解,剩下的“工厂逻辑”全由框架处理。Spring 的 BeanFactory 本质上就是一个超级强大的简单工厂,配合配置文件或注解,实现了比传统工厂方法更灵活的扩展性。


    五、避坑指南与最佳实践

  • 拒绝过度设计: 如果你的系统只有 3 种类型,且一年都不会变,强行套用“工厂方法”搞出 6 个类,那是过度设计,会被同事吐槽的。简单工厂 + 静态方法往往更香。

  • 善用静态工厂方法: 《Effective Java》强烈推荐用静态工厂方法代替构造器。例如:

    // 推荐写法
    LocalDate date = LocalDate.now();
    Optional<String> opt = Optional.of("value");
    // 而不是 new LocalDate() 或 new Optional()

    这其实就是简单工厂的最佳实践。

  • 结合策略模式: 在实际业务中,工厂模式常与策略模式搭配使用。例如文件上传场景,通过工厂根据配置(OSS、S3、本地)返回不同的上传策略对象,再结合 Spring 的 List<Service> 自动注入,可以实现零 if-else 的优雅代码。


  • 六、总结

    工厂模式是面向对象设计的基石之一。

    • 思想上:推崇工厂方法,理解其“开闭原则”和“依赖倒置”的精髓,这是面试和架构设计的加分项。
    • 行动上:日常开发首选 Spring 依赖注入,其次是 简单工厂(静态方法)。
    • 口诀:“能注入就注入,不能注入写个静态方法,除非你在写框架。”

    希望这篇文章能帮你理清工厂模式的脉络,在实际项目中做出最合适的技术选型。

    赞(0)
    未经允许不得转载:171主机测评 » Java设计模式实战:工厂模式,从“Hello World”到企业级架构的正确打开方式
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址