软件设计模式修炼 -- 抽象工厂模式


抽象工厂模式是常见的建造型设计模式之一,比工厂方法模式抽象程度更高。工厂方法模式中具体工厂只生产一种具体产品,但在抽象工厂模式中,具体工厂可以生产相关的一组具体产品,这样一组产品称为产品族,产品族中的每一个产品分属于某一产品继承等级结构。


模式动机

有时候我们需要一个工厂提供多个产品对象,而不是单一一个产品对象,如一个电器设备工厂,它可以生产电视机、电冰箱、空调等设备,而不只是生成某种类型的电器。为了更清晰地理解抽象工厂模式,这里先引入两个概念:

  1. 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、TCL电视机等,抽象电视机与具体品牌电视机之间构成了一个产品等级结构。

  2. 产品族:指由同一工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产海尔电视机、海尔电冰箱,则它们是同一产品族,各自位于不同产品等级结构。

产品族

当系统提供的工厂生产的具体产品不是一个简单对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。


模式定义

提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。


模式结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dhyAERw4-1583586756776)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20200307160832169.png)]

  1. AbstractFacory(抽象工厂)

    抽象工厂用于声明生产抽象产品的方法,在一个抽象工厂中可以定义一组方法,每一方法对应一个产品等级结构

  2. ConcreteFactory(具体工厂)

    具体工厂实现抽象工厂声明的生产抽象产品的方法,生产一组具体产品,这些产品构成一个产品族,每一个产品都位于某个产品等级结构中。

  3. AbstractProduct(抽象产品)

    抽象产品为每种产品声明接口,在抽象产品中定义产品的抽象业务方法

  4. ConcreteProduct(具体产品)

    具体产品定义具体工厂生产的具体产品对象,实现抽象产品接口中定义的业务方法。


抽象工厂模式实例之电器工厂

  1. 实例说明

    一个电器工厂可以产生多种类型的电器,如海尔工厂可以生产海尔电视机、海尔空调等,TCL工厂可以生产TCL电视机、TCL空调等,相同品牌的电器构成一个产品族,而相同类型电器构成一个产品等级结构。

  2. 实例代码及解释

    1. 抽象产品类Television

      public interface Television {
      
          void play();
      }
      
    2. 具体产品类HairTelevision(海尔电视机类)

      public class HairTelevision implements Television {
      
          @Override
          public void play() {
      
              System.out.println("海尔电视机播放中......");
          }
      }
      
    3. 具体产品类TCLTelevision(TCL电视机类)

      public class TCLTelevision implements Television {
      
          @Override
          public void play() {
      
              System.out.println("TCL电视机播放中.......");
          }
      }
      
    4. 抽象产品类AirConditioner

      public interface AirConditioner {
      
          void changeTemperature();
      }
      
    5. 具体产品类HairAirConditioner(海尔空调类)

      public class HairAirConditioner implements AirConditioner {
      
          @Override
          public void changeTemperature() {
              System.out.println("海尔空调温度改变中.....");
          }
      }
      
    6. 具体产品类TCLAirConditioner(TCL空调类)

      public class TCLAirConditioner implements AirConditioner {
      
          @Override
          public void changeTemperature() {
              System.out.println("TCL空调温度改变中......");
          }
      }
      
    7. 抽象工厂类EFactory

      public interface EFactory {
      
          Television produceTelevision();
         
          AirConditioner produceAirConditioner();
         }
      
    8. 具体工厂类HairFactory(海尔工厂类)

      public class HairFactory implements EFactory {
      
          @Override
          public Television produceTelevision() {
              return new HairTelevision();
          }
      
          @Override
          public AirConditioner produceAirConditioner() {
              return new HairAirConditioner();
          }
      }
      
    9. 具体工厂类TCLPFactory

      public class TCLFactory implements EFactory {
      
          @Override
          public Television produceTelevision() {
              return new TCLTelevision();
          }
      
       @Override
          public AirConditioner produceAirConditioner() {
           return new TCLAirConditioner();
          }
      }
      
    10. XML操作工具类

      public class XMLUtil {
         
             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(factoryName);
                 Object o = c.newInstance();
                 return o;
             }
         }
      
    11. 配置文件

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

      public class Test {
      
          public static void main(String[] args) throws Exception {
      
              EFactory factory = (EFactory) XMLUtil.getBean();
      
              Television television = factory.produceTelevision();
      
              television.play();
      
              AirConditioner airConditioner = factory.produceAirConditioner();
      
              airConditioner.changeTemperature();
          }
      }
      
    13. 结果分析

      如果在配置文件将节点中内容设置为 HairFactory,则输出结果如下:
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tPoxjd7a-1583586756777)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20200307174255434.png)]

      如果在配置文件将节点中内容设置为 TCLFactory,则输出结果如下:
      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fZc1As2U-1583586756779)(C:\Users\LENOVO\AppData\Roaming\Typora\typora-user-images\image-20200307174351784.png)]

      如果需要增加新品牌的电器,即增加一个新的产品族,如增加海信电视机和海信空调,则只需对应增加一个具体工厂,再将配置文件中具体工厂类名修改为新增工厂类名,原有代码无须修改。但如果要增加新的产品,如增加新的电器产品洗衣机,抽象工厂需要声明一个生产洗衣机的方法,所有具体工厂类都需实现该方法,将导致系统不再符合开闭原则。


posted @ 2020-03-07 21:15  低吟不作语  阅读(806)  评论(0编辑  收藏  举报