抽象工厂模式vs工厂方法模式

  1. 工厂方法模式中具体工厂只需要生产一种具体产品
  2. 抽象工厂模式中具体工厂可以生产相关的一组具体产品,这样的一组产品称为产品族

引入两个概念

产品等级结构

产品等级结构:产品的继承结构。

比如:抽象电视机和具体品牌电视之间构成了一个产品等级结构
在这里插入图片描述

产品族

产品族:是指由同一个工厂生产的,位于不同产品等级结构一组产品

比如:
① 海尔工厂生成的海尔电视机、海尔电冰箱。
海尔电视机、海尔电冰箱就属于同一个产品族
③ 在这里海尔电视机属于电视机产品等级结构,海尔电冰箱属于电冰箱等级结构 ,它们位于不同产品等级结构
在这里插入图片描述

模式结构的角色

  1. 抽象工厂

① 定义了返回具体产品对象的方法
产品有几种就定义几个方法

  1. 具体工厂

① 实现父类中 返回具体产品对象的方法
具体工厂的个数 = 产品族的个数 --> 品牌的个数

  1. 抽象产品

① 将业务方法抽象出来
抽象产品的个数 = 产品等级结构的个数 -->电视机、电冰箱 (产品类别的个数)

  1. 具体产品

① 只要指明一个产品所处的产品族,以及所属的产品等级结构,就可以唯一确定这个产品
② 实现该产品的业务方法
具体产品的个数 = 产品族个数(品牌) * 产品等级结构的个数(产品类别)
比如品牌(产品族)有两个:海尔和海信
抽象产品(产品等级结构)有两个:电视机、电冰箱
则具体产品就是2 * 2

抽象工厂模式案例

案例背景

计算机包含内存(RAM),CPU等硬件设备,根据如图所示的“产品等级结构-产品族示意图”,使用抽象工厂模式实现计算机设备创建过程并绘制类图
在这里插入图片描述

案例分析

  1. 产品族(即具体工厂 --> 品牌)的个数有两个:PC 和 MAC
  2. 产品等级结构(即抽象产品 --> 产品类别)的个数有两个:CPU 和 RAM

实现步骤

  1. 编写一个抽象工厂类:AbstractFactory,
    两个具体工厂:PcFactory和MacFactory ,
    两个抽象产品类:CPU,RAM,
    四个具体产品类:PcCPU,MacCPU,PcRAM,MacRAM
  2. 编写一个用户类Client和辅助类XMLUtil以实现通过XML文件来制造不同的产品
  3. 更改XML中的属性,观察用户类是否能使用不同的产品

代码实现(按顺序)

文件结构/类图

在这里插入图片描述

在这里插入图片描述

1. 抽象产品类(2个)

/**
 * @author 王胖子
 * @version 1.0
 */
public interface CPU {
    public void play();
}

/**
 * @author 王胖子
 * @version 1.0
 */
public interface RAM {
    public void play();
}

2. 具体产品类(4个)

一个具体工厂生产一个产品族,一个产品族里有两种产品:CPU和RAM
② 有两个具体工厂:PC工厂 和 MAC工厂
PC工厂生产 PcCPU 和 PcRAM

/**
 * @author 王胖子
 * @version 1.0
 */
public class PcCPU implements CPU {
    @Override
    public void play() {
        System.out.println("PC的CPU工作中...");
    }
}
/**
 * @author 王胖子
 * @version 1.0
 */
public class PcRAM implements RAM {
    @Override
    public void play() {
        System.out.println("PC的RAM工作中...");
    }
}

/**
 * @author 王胖子
 * @version 1.0
 */
public class MacCPU implements CPU {
    @Override
    public void play() {
        System.out.println("MAC的CPU工作中...");
    }
}

/**
 * @author 王胖子
 * @version 1.0
 */
public class MacRAM implements RAM {
    @Override
    public void play() {
        System.out.println("MAC的RAM工作中...");
    }
}

3. 抽象工厂(1个)

/**
 * @author 王胖子
 * @version 1.0
 */
public interface AbstractFactory {
    public CPU produceCPU();
    public RAM produceRAM();
}

4. 具体工厂(2个)

/**
 * @author 王胖子
 * @version 1.0
 */
public class PcFactory implements AbstractFactory {
    @Override
    public CPU produceCPU() {
        return new PcCPU();
    }

    @Override
    public RAM produceRAM() {
        return new PcRAM();
    }
}

/**
 * @author 王胖子
 * @version 1.0
 */
public class MacFactory implements AbstractFactory {
    @Override
    public CPU produceCPU() {
        return new MacCPU();
    }

    @Override
    public RAM produceRAM() {
        return new MacRAM();
    }
}

5. 配置类(config.xml)

<?xml version="1.0"?>
<config>
    <className>PcFactory</className>
</config>

6. 读取配置类(XMLUtil.java)

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.File;

/**
 * @author 王胖子
 * @version 1.0
 */
public class XMLUtil {
    //该方法用于从xml配置文件中提取具体类类名,并返回一个实例对象
    public static Object getBean() {
        try {
            //创建DOM对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            //这个地址从项目根目录开始读取
            doc = builder.parse(new File("src//config.xml"));

            //获取包含类名的文本节点
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = classNode.getNodeValue();

            //通过类名生成实例对象并返回
            Class c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

7. 客户类

/**
 * @author 王胖子
 * @version 1.0
 */
public class Client {
    public static void main(String[] args) {
        CPU cpu;
        RAM ram;
        AbstractFactory factory;
        factory = (AbstractFactory) XMLUtil.getBean();
        cpu = factory.produceCPU();
        ram = factory.produceRAM();
        cpu.play();
        ram.play();
    }
}

输出结果

在这里插入图片描述

模式适用环境

抽象工厂模式主要适用于:

  1. 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节
  2. 系统中有多于一个的产品族,但每次只使用其中某一产品族
  3. 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来
  4. 产品等级结构稳定,在设计完成之后不会向系统中增加新的产品等级结构或者删除已有的产品等级结构
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐