工厂方法模式示例 (代码实现)

这个示例以生产电视机为例,完整地展示了工厂方法模式的四个角色是如何通过代码实现的。

a. 代码结构与实现分析

在这里插入图片描述

  • 角色1: Product (抽象产品)

    • 代码: public abstract class Product { public abstract void productMethod(); }
    • 解析: 这里定义了一个抽象类 Product,它代表了所有产品的通用接口。在这个例子中,可以理解为“电视机”。它包含一个抽象方法 productMethod(),可以理解为电视机的通用功能,比如“播放”。
  • 角色2: ConcreteProduct (具体产品)

    • 代码: class ConcreteProduct extends Product { @Override public void productMethod() { System.out.println("海尔电视机播放中......"); } }
    • 解析: ConcreteProduct 类继承了 Product 抽象类,并实现了 productMethod() 方法。这代表一个具体的产品,即“海尔电视机”。当调用它的 productMethod() 时,它会执行自己特定的业务逻辑。
  • 角色3: Creator (抽象工厂)

    • 代码: abstract class Creator { public abstract Product factoryMethod(); }
    • 解析: 这里定义了一个抽象工厂 Creator,它声明了一个核心的工厂方法 factoryMethod()。这个方法的返回类型是抽象产品 Product。它只负责定义创建产品的接口,但不负责实现,将具体的创建过程延迟到子类中。
  • 角色4: ConcreteCreator (具体工厂)

    • 代码: class ConcreteCreator extends Creator { @Override public Product factoryMethod() { System.out.println("海尔电视机工厂生产海尔电视机。"); return new ConcreteProduct(); } }
    • 解析: ConcreteCreator 继承了抽象工厂 Creator,并实现了 factoryMethod()。它的职责非常明确:创建并返回一个具体的 ConcreteProduct 实例。在这个例子中,“海尔电视机工厂”(ConcreteCreator) 专门负责生产“海尔电视机”(ConcreteProduct)。
b. 客户端实现与模式精髓

在这里插入图片描述

图片描述:展示了Client类的main方法,其中有两种创建Creator的方式,一种是直接new,另一种是被注释掉的、推荐使用的“XML+Java反射”方式。下方显示了程序的运行结果。

客户端 (Client) 的代码是理解工厂方法模式如何实现解耦和开闭原则的关键。

  • 客户端职责: 客户端的目的是使用产品,而不是关心产品是如何被创建的。

  • 实现方式一:直接实例化具体工厂 (不够灵活)

    • 代码:
      //面向抽象编程,提高了程序的灵活性;不使用“XML+Java反射”方式
      Creator creator = new ConcreteCreator(); //可以选择其它的具体创建者
      Product product = creator.factoryMethod(); //创建产品
      product.productMethod(); //使用产品方法
      
    • 解析:
      1. 客户端代码首先 new 了一个具体工厂 ConcreteCreator
      2. 然后通过这个工厂实例调用 factoryMethod() 来获得一个 Product 对象。
      3. 最后调用产品的 productMethod() 方法。
    • 总结: 这种方式虽然实现了产品创建和使用的分离(客户端只知道 Product 接口,不知道 ConcreteProduct),但客户端代码硬编码new ConcreteCreator(),即客户端与具体工厂发生了耦合。如果现在需要换成“海信电视机工厂”,就必须修改客户端的这行代码,这在一定程度上还是违反了开闭原则。
  • 实现方式二:XML配置文件 + Java反射 (推荐方式)

    • 代码:
      //推荐使用“XML配置文件+Java反射”方式
      //当新增产品时,只需要同时创建具体产品类及相应的具体工厂类,并对配置文件做相应地修改
      try {
          Creator creator = (Creator) XMLUtil.getBean(); //强制类型转换
          Product product = creator.factoryMethod(); //调用抽象方法
          product.productMethod(); //调用抽象方法
      } catch (Exception e) {
          System.out.println(e.getMessage());
      }
      
    • 解析:
      1. 这种方式是工厂方法模式的最佳实践。客户端代码中不再出现任何具体工厂的类名。
      2. 具体使用哪个工厂,是由一个外部的XML配置文件来决定的。例如,XML文件中可能写着 <className>com.example.ConcreteCreator</className>
      3. XMLUtil.getBean() 方法(一个辅助工具类)会读取这个XML文件,获取其中配置的类名字符串。
      4. 然后,它利用Java的反射机制,根据这个字符串动态地创建该类的实例。
      5. 客户端代码拿到这个实例后,向上转型为抽象工厂 Creator,然后就可以正常使用了。
    • 总结: 这是实现开闭原则的终极形态。如果现在需要将“海尔电视机”换成“海信电视机”,我们只需要:
      1. 新增 HisenseProduct 类和 HisenseCreator 类。
      2. 只修改XML配置文件中的类名为 com.example.HisenseCreator
      3. 客户端的 Client.java 代码完全不需要任何修改,甚至不需要重新编译
        这使得系统在扩展新产品时,真正做到了对修改关闭,对扩展开放。
  • 运行结果分析

    • 海尔电视机工厂生产海尔电视机。 — 这是 ConcreteCreatorfactoryMethod 被调用时打印的。
    • 海尔电视机播放中...... — 这是 Client 在获得 Product 对象后,调用其 productMethod 时打印的。
    • 这个结果清晰地展示了“先由具体工厂创建产品,再由客户端使用产品”的完整流程。
Logo

北京人形旗下天工造物具身智能开源社区,聚焦具身天工与慧思开物两大平台

更多推荐