软件设计模式修炼 -- 工厂方法模式

2年前 (2022) 程序员胖胖胖虎阿
332 0 0

工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时弥补了简单工厂的缺陷,更好地符合开闭原则的要求,增加新的具体产品对象不需要对已有系统作任何修改。

模式定义

工厂方法模式又称为工厂模式,也叫虚拟构造器模式或者多态工厂模式,属于类创建模式。在工厂模式中,工厂父类负责定义产品对象的公共接口,而子工厂模式负责生成具体的产品对象,这样做的目的是将产品类实例化操作延迟到工厂子类中完成,即通过工厂子类来确定实例化哪一个对象。

模式结构

软件设计模式修炼 -- 工厂方法模式

  1. Product(抽象产品)

    抽象产品是定义产品的接口,是工厂方法模式所创建对象的超类型,也就是产品对象的共同父类接口

  2. ConcreteProduct(具体产品)

    具体产品实现抽象产品接口,某种类型的具体产品由专门具体创建

  3. Facory(抽象工厂)

    在抽象工厂类中,声明工厂方法,用于返回一个产品。抽象工厂是工厂方法模式的核心,任何在模式中创建对象的工厂类都必须实现该接口。

  4. ConcreteFactory(具体工厂)

    具体工厂是抽象工厂类的子类,实现了抽象工厂定义的工厂方法,返回一个具体产品类的实例。

模式分析

在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建的工作交给了子类。核心类仅仅给出具体工厂实现的接口,而不负责哪一个产品被实例化的细节,使得工厂方法模式允许系统在不修改工厂角色的情况下引进新产品。

实际的开发应用中,不直接使用new关键字来创建对象,而是将具体类的类名写入配置文件,在通过java反射机制,读取XML格式的配置文件,根据存储在XML文件的类名字符串生成对象。

工厂方法模式实例之手机工厂

  1. 实例说明

    之前的简单工厂模式时我们也创建过一个类似实例,但却是违反了开闭原则的。通过工厂方法模式进行一次重构,将原有工厂进行分割,为每种品牌的手机提供一个子工厂,使整个系统具有更好的灵活性和可扩展性。

  2. 实例类图

    软件设计模式修炼 -- 工厂方法模式

  3. 实例代码及解释

    1. 抽象产品类Phone

      public abstract class Phone {
      
          public abstract void use();
      }
      
    2. 具体产品类HuaweiPhone

      public class HuaweiPhone extends Phone {
      
          @Override
          public void use() {
      
              System.out.println("华为手机使用中....");
          }
      }
      
    3. 具体产品类XiaomiPhone

      public class XiaomiPhone extends Phone {
      
          @Override
          public void use() {
      
              System.out.println("小米手机使用中....");
          }
      }
      
    4. 抽象工厂类PhoneFactory

      public interface PhoneFactory {
      
          Phone producePhone();
      }
      
    5. 具体工厂类HuaweiPFactory

      public class HuaweiPFactory implements PhoneFactory {
          @Override
          public Phone producePhone() {
              System.out.println("华为工厂生产华为手机......");
              return new HuaweiPhone();
          }
      }
      
    6. 具体工厂类XiaomiPFactory

      public class XiaomiPFactory implements PhoneFactory {
      
          @Override
          public Phone producePhone() {
      
              System.out.println("小米工厂生产小米手机......");
              return new XiaomiPhone();
          }
      
      }
      
    7. XML操作工具类

      public class XMLUtilPhone {
      
          public static Object getBean() throws Exception {
      
              //创建解析器工厂
              DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance();
              //创建解析器
              DocumentBuilder builder = builderFactory.newDocumentBuilder();
              //得到document
              Document document = builder.parse("configPhone.xml");
              //获取包含品牌名称的文本节点
              NodeList brandNameList = document.getElementsByTagName("factoryName");
              Node classNode = brandNameList.item(0).getFirstChild();
              String factoryName = classNode.getNodeValue().trim();
      
      //        System.out.println(factoryName);
      
              Class c = Class.forName("com.factoryMethod." + factoryName);
              Object o = c.newInstance();
              return o;
          }
      }
      
    8. 配置文件

      <?xml version="1.0" encoding="UTF-8" ?>
      <configuration>
         <factoryName>XiaomiPFactory</factoryName>
      </configuration>
      
    9. 测试类

      public class Test {
      
          public static void main(String[] args) throws Exception {
      
              PhoneFactory phoneFactory = (PhoneFactory) XMLUtilPhone.getBean();
      
              Phone phone = phoneFactory.producePhone();
      
              phone.use();
          }
      }
      
    10. 结果分析

      如果在配置文件将节点中内容设置为 XiaomiPFactory,则输出结果如下:
      软件设计模式修炼 -- 工厂方法模式
      如果在配置文件将节点中内容设置为 XiaomiPFactory,则输出结果如下:
      软件设计模式修炼 -- 工厂方法模式
      如果需要增加新的类型的手机,则首先要增加一个新的具体产品类,再增加对于的具体工厂类。

模式优缺点

工厂方法模式优点:

  • 工厂方法为用户创建客户所需的产品,向客户隐藏了具体产品类被实例化的细节
  • 基于接口开发的工厂角色和产品角色实现了多态性设计
  • 向系统加入新产品时,无须修改抽象工厂和抽象产品提供的接口,也无须修改其他具体工厂和产品,只要添加一个具体工厂和具体产品即可,完全符合开闭原则

工厂方法模式缺点:

  • 添加新产品时,需要提供新的具体产品类和对应的具体工厂类,类的个数会成对增加,增加系统复杂性
  • 更多的类需要编译和运行,给系统带来额外的开销

模式适用环境

以下情况可以使用工厂方法模式:

  • 一个类不知道它所需要的类的对象,客户端不需要知道具体产品类的类名,只需知道所对应的工厂即可
  • 一个类通过其子类来指定创建哪个对象,对于抽象工厂类只需提供一个创建产品的接口,由其子类来确定具体要创建的对象

模式应用

在 Java 集合框架中,常用的 List 和 Set 等集合都实现了 Collection 接口,Collection 接口为所有的 Java 集合类定义了一个 iterator() 方法,可返回一个用于遍历集合 Iterator(迭代器)类型的对象。而 Java 集合类可以实现该 iterator() 方法来返回一个具体的迭代器对象。

软件设计模式修炼 -- 工厂方法模式

实际的过程实现相对复杂,这里仅给出简化版,List 接口除了继承 Collection 接口的 iterator() 方法外,还增加了新的工厂方法 listIterator(),专门用于创建 ListIterator 类型的迭代器,在 List 的子类 LinkedList 在实现了该方法,可用于创建 ListIterator 子类 ListItr 的对象并返回,是一个具体的工厂方法

public ListIterator<E> listIterator(int index) {
    return new ListItr(index);
}

在 JDBC 中也大量使用了工厂方法模式,在创建连接对象 Connection、Statement、ResultSet 时都使用了工厂方法

Connection con = DriveManager.getConnection(".....");
Statement statement = con.createStatement();
ResultSet rs = statement.executeQuery(".....")

版权声明:程序员胖胖胖虎阿 发表于 2022年9月12日 下午2:56。
转载请注明:软件设计模式修炼 -- 工厂方法模式 | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...