4.4创建型模式————抽象工厂模式

2023-11-09

前面介绍的工厂方法模式中考虑的是一类产品的生产,如畜牧场只养动物、电视机厂只生产电视机、计算机软件学院只培养计算机软件专业的学生等。

同种类称为同等级,也就是说:工厂方法模式只考虑生产同等级的产品,但是在现实生活中许多工厂是综合型的工厂,能生产多等级(种类) 的产品,如农场里既养动物又种植物,电器厂既生产电视机又生产洗衣机或空调,大学既有软件专业又有生物专业等。

本节要介绍的抽象工厂模式将考虑多等级产品的生产,将同一个具体工厂所生产的位于不同等级的一组产品称为一个产品族,图 1 所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
 

电器工厂的产品等级与产品族
图1 电器工厂的产品等级与产品族

模式的定义与特点

抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。

抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

使用抽象工厂模式一般要满足以下条件。

  • 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
  • 系统一次只可能消费其中某一族产品,即同族的产品一起使用。


抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。

  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
  • 当增加一个新的产品族时不需要修改原代码,满足开闭原则。


其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。

模式的结构与实现

抽象工厂模式同工厂方法模式一样,也是由抽象工厂、具体工厂、抽象产品和具体产品等 4 个要素构成,但抽象工厂中方法个数不同,抽象产品的个数也不同。现在我们来分析其基本结构和实现方法。

1. 模式的结构

抽象工厂模式的主要角色如下。

  1. 抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。
  2. 具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。
  3. 抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。
  4. 具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它 同具体工厂之间是多对一的关系。


抽象工厂模式的结构图如图 2 所示。
 

抽象工厂模式的结构图
图2 抽象工厂模式的结构图

2. 模式的实现

从图 2 可以看出抽象工厂模式的结构同工厂方法模式的结构相似,不同的是其产品的种类不止一个,所以创建产品的方法也不止一个。下面给出抽象工厂和具体工厂的代码。

(1) 抽象工厂:提供了产品的生成方法。

 
interface AbstractFactory
{
public Product1 newProduct1();
public Product2 newProduct2();
}


(2) 具体工厂:实现了产品的生成方法。

class ConcreteFactory1 implements AbstractFactory
{
public Product1 newProduct1()
{
System.out.println("具体工厂 1 生成-->具体产品 11...");
return new ConcreteProduct11();
}
public Product2 newProduct2()
{
System.out.println("具体工厂 1 生成-->具体产品 21...");
return new ConcreteProduct21();
}
}

模式的应用实例

【例1】用抽象工厂模式设计农场类。

分析:农场中除了像畜牧场一样可以养动物,还可以培养植物,如养马、养牛、种菜、种水果等,所以本实例比前面介绍的畜牧场类复杂,必须用抽象工厂模式来实现。

本例用抽象工厂模式来设计两个农场,一个是韶关农场用于养牛和种菜,一个是上饶农场用于养马和种水果,可以在以上两个农场中定义一个生成动物的方法 newAnimal() 和一个培养植物的方法 newPlant()。

对马类、牛类、蔬菜类和水果类等具体产品类,由于要显示它们的图像(点此下载图片),所以它们的构造函数中用到了 JPanel、JLabel 和 ImageIcon 等组件,并定义一个 show() 方法来显示它们。

客户端程序通过对象生成器类 ReadXML 读取 XML 配置文件中的数据来决定养什么动物和培养什么植物(点此下载 XML 文件)。其结构图如图 3 所示。
 

农场类的结构图
图3 农场类的结构图


程序代码如下:

 
  1. package AbstractFactory;
    import java.awt.*;
    import javax.swing.*;
    public class FarmTest
    {
    public static void main(String[] args)
    {
    try
    {
    Farm f;
    Animal a;
    Plant p;
    f=(Farm) ReadXML.getObject();
    a=f.newAnimal();
    p=f.newPlant();
    a.show();
    p.show();
    }
    catch(Exception e)
    {
    System.out.println(e.getMessage());
    }
    }
    }
    //抽象产品:动物类
    interface Animal
    {
    public void show();
    }
    //具体产品:马类
    class Horse implements Animal
    {
    JScrollPane sp;
    JFrame jf=new JFrame("抽象工厂模式测试");
    public Horse()
    {
    Container contentPane=jf.getContentPane();
    JPanel p1=new JPanel();
    p1.setLayout(new GridLayout(1,1));
    p1.setBorder(BorderFactory.createTitledBorder("动物:马"));
    sp=new JScrollPane(p1);
    contentPane.add(sp, BorderLayout.CENTER);
    JLabel l1=new JLabel(new ImageIcon("src/A_Horse.jpg"));
    p1.add(l1);
    jf.pack();
    jf.setVisible(false);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
    }
    public void show()
    {
    jf.setVisible(true);
    }
    }
    //具体产品:牛类
    class Cattle implements Animal
    {
    JScrollPane sp;
    JFrame jf=new JFrame("抽象工厂模式测试");
    public Cattle() {
    Container contentPane=jf.getContentPane();
    JPanel p1=new JPanel();
    p1.setLayout(new GridLayout(1,1));
    p1.setBorder(BorderFactory.createTitledBorder("动物:牛"));
    sp=new JScrollPane(p1);
    contentPane.add(sp, BorderLayout.CENTER);
    JLabel l1=new JLabel(new ImageIcon("src/A_Cattle.jpg"));
    p1.add(l1);
    jf.pack();
    jf.setVisible(false);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
    }
    public void show()
    {
    jf.setVisible(true);
    }
    }
    //抽象产品:植物类
    interface Plant
    {
    public void show();
    }
    //具体产品:水果类
    class Fruitage implements Plant
    {
    JScrollPane sp;
    JFrame jf=new JFrame("抽象工厂模式测试");
    public Fruitage()
    {
    Container contentPane=jf.getContentPane();
    JPanel p1=new JPanel();
    p1.setLayout(new GridLayout(1,1));
    p1.setBorder(BorderFactory.createTitledBorder("植物:水果"));
    sp=new JScrollPane(p1);
    contentPane.add(sp, BorderLayout.CENTER);
    JLabel l1=new JLabel(new ImageIcon("src/P_Fruitage.jpg"));
    p1.add(l1);
    jf.pack();
    jf.setVisible(false);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
    }
    public void show()
    {
    jf.setVisible(true);
    }
    }
    //具体产品:蔬菜类
    class Vegetables implements Plant
    {
    JScrollPane sp;
    JFrame jf=new JFrame("抽象工厂模式测试");
    public Vegetables()
    {
    Container contentPane=jf.getContentPane();
    JPanel p1=new JPanel();
    p1.setLayout(new GridLayout(1,1));
    p1.setBorder(BorderFactory.createTitledBorder("植物:蔬菜"));
    sp=new JScrollPane(p1);
    contentPane.add(sp, BorderLayout.CENTER);
    JLabel l1=new JLabel(new ImageIcon("src/P_Vegetables.jpg"));
    p1.add(l1);
    jf.pack();
    jf.setVisible(false);
    jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//用户点击窗口关闭
    }
    public void show()
    {
    jf.setVisible(true);
    }
    }
    //抽象工厂:农场类
    interface Farm
    {
    public Animal newAnimal();
    public Plant newPlant();
    }
    //具体工厂:韶关农场类
    class SGfarm implements Farm
    {
    public Animal newAnimal()
    {
    System.out.println("新牛出生!");
    return new Cattle();
    }
    public Plant newPlant()
    {
    System.out.println("蔬菜长成!");
    return new Vegetables();
    }
    }
    //具体工厂:上饶农场类
    class SRfarm implements Farm
    {
    public Animal newAnimal()
    {
    System.out.println("新马出生!");
    return new Horse();
    }
    public Plant newPlant()
    {
    System.out.println("水果长成!");
    return new Fruitage();
    }
    }
    

     

  1. package AbstractFactory;
    import javax.xml.parsers.*;
    import org.w3c.dom.*;
    import java.io.*;
    class ReadXML
    {
    public static Object getObject()
    {
    try
    {
    DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
    DocumentBuilder builder=dFactory.newDocumentBuilder();
    Document doc;
    doc=builder.parse(new File("src/AbstractFactory/config.xml"));
    NodeList nl=doc.getElementsByTagName("className");
    Node classNode=nl.item(0).getFirstChild();
    String cName="AbstractFactory."+classNode.getNodeValue();
    System.out.println("新类名:"+cName);
    Class<?> c=Class.forName(cName);
    Object obj=c.newInstance();
    return obj;
    }
    catch(Exception e)
    {
    e.printStackTrace();
    return null;
    }
    }
    }

     


程序运行结果如图 4 所示。
 

农场养殖的运行结果
图4 农场养殖的运行结果

模式的应用场景

抽象工厂模式最早的应用是用于创建属于不同操作系统的视窗构件。如 java 的 AWT 中的 Button 和 Text 等构件在 Windows 和 UNIX 中的本地实现是不同的。

抽象工厂模式通常适用于以下场景:

  1. 当需要创建的对象是一系列相互关联或相互依赖的产品族时,如电器工厂中的电视机、洗衣机、空调等。
  2. 系统中有多个产品族,但每次只使用其中的某一族产品。如有人只喜欢穿某一个品牌的衣服和鞋。
  3. 系统中提供了产品的类库,且所有产品的接口相同,客户端不依赖产品实例的创建细节和内部结构。

模式的扩展

抽象工厂模式的扩展有一定的“开闭原则”倾斜性:

  1. 当增加一个新的产品族时只需增加一个新的具体工厂,不需要修改原代码,满足开闭原则。
  2. 当产品族中需要增加一个新种类的产品时,则所有的工厂类都需要进行修改,不满足开闭原则。


另一方面,当系统中只存在一个等级结构的产品时,抽象工厂模式将退化到工厂方法模式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

4.4创建型模式————抽象工厂模式 的相关文章

  • 【使用kubeadm安装部署K8S】

    问题 使用kubeadm安装部署K8S 该篇文章介绍利用kubeadm进行安装部署K8S 方法 1 准备环境 软件环境 软件 版本 操作系统 CentOS7 9 x64 mini Docker 19 ce Kubernetes 1 20 服
  • MFC中使用CBitmap类进行绘图

    大家看名字就可以知道 这个类是用来绘制位图的 即以 bmp 为后缀的图片 一般游戏之中 需要使用的图片比较多 都会将图片先存为文件 然后从文件中读取 而从文件中读取图片的步骤有以下几步 1 建立一个与窗口DC兼容的内存DC 我们加载的图片是

随机推荐

  • 推荐几个Python爬虫接单渠道

    说起兼职 我有一位做了4年Python工程师的朋友 爬虫做副业起码挣了20W 写各种奇葩爬虫挣钱 爬虫兼职方式多 单也很多 首先是爬虫外包活 国内有平台接单 价格500 4000不等 也可以帮互联网运营爬数据做网站 那群人一天到晚死磕数据
  • CXF拦截器

    引言 CXF拦截器是Apache CXF里面一个很重要的功能 它能够动态操作响应数据和请求数据 降低代码的耦合性 提供代码的内聚性 这对于CXF这个以处理消息为中心的服务框架来说是非常有用的 CXF通过在Interceptor中对消息进行特
  • mysql 创建订单表语句_MySQL创建表语句

    表 t admin tabs 列信息 Field Type Collation Null Key Default Extra Privileges Comment admin id int 11 unsigned NULL NO PRI N
  • local reference table overflow 内存泄露

    local reference table overflow JNI层coding经常会遇到ReferenceTable overflow问题 特别是当jni函数被反复调用上千上万次的时候 现汇总如下 未完待续 并欢迎补充 嘻嘻 总体原则
  • FileZilla连接阿里云服务器:尝试连接“ECONNREFUSED - 连接被服务器拒绝”失败

    4 FileZilla连接阿里云服务器 目的 可以更好的管理云文件 1 在远程服务器端通过指令vim etc ssh sshd config开放22号端口 2 设置云服务器的安全组ID 添加20 21 3 然后启动FileZilla 新建站
  • 6.143 指针习题10

    关于二维数组 指针运算问题 注意二维指针需要解两次引用 即第 0 个元素是 a 见下例 include
  • android studio 监听返回键,最强 Android Studio 使用小技巧和快捷键

    第一步 新建一个project 或者如果你已经有project的话 那就直接新建一个module 注意选择Java library 然后下一步 第二步 编写MyClass java 第三步 在MyClass java文件右击 选择run M
  • getjson ajax webpy,ajaxwebpy

    ajaxweb py is a framework for the library web py It which makes it very easy to make sites interactive using AJAX techno
  • 手机有时触摸失灵解决方法

    1 屏幕不干净造成的屏幕不灵敏 用干净的无尘布将手机上的脏污 水渍擦拭干净 2 手机有贴膜 确认用户是否贴膜之后出现屏幕失灵问题 可将膜去掉再使用对比 3 操作耽搁软件时屏幕失灵 可备份好软件数据 进入设置 应用与权限 更多设置 应用管理
  • seed+transformer+finetune+图文融合+VLP+Prompt Learning整合

    1 Seed 在神经网络中 参数默认是进行随机初始化的 不同的初始化参数往往会导致不同的结果 如果不设置的话每次训练时的初始化都是随机的 导致结果不确定 当得到比较好的结果时我们通常希望这个结果是可以复现的 如果设置初始化 则每次初始化都是
  • 剑指 Offer 66. 构建乘积数组(java+python)

    给定一个数组 A 0 1 n 1 请构建一个数组 B 0 1 n 1 其中 B i 的值是数组 A 中除了下标 i 以外的元素的积 即 B i A 0 A 1 A i 1 A i 1 A n 1 不能使用除法 示例 输入 1 2 3 4 5
  • jmeter性能测试——性能的评定标准

    性能的评定标准 性能指标 响应时间 指的是从客户端发出请求开始 到接收到服务器的响应 并且看到响应的内容为止 这个时间段 称为响应时间 响应时间 网络传输的时间 服务器处理的时间 浏览器解析呈现的时间 如何弱化网络传输的时间和浏览器解析呈现
  • PackageInstaller 原理简

    http topic csdn net u 20110410 23 43571CFA 87B2 4E36 880C 1FA499BA32B0 html 应用安装是智能机的主要特点 即用户可以把各种应用 如游戏等 安装到手机上 并可以对其进行
  • 华为OD机试 - 任务最优调度(Java)

    题目描述 给定一个正整数数组表示待系统执行的任务列表 数组的每一个元素代表一个任务 元素的值表示该任务的类型 请计算执行完所有任务所需的最短时间 任务执行规则如下 任务可以按任意顺序执行 且每个任务执行耗时间均为1个时间单位 两个同类型的任
  • Nuxt 3.0 全栈开发:五种数据获取 API 选择和应用最佳实践

    Nuxt 3 0 全栈开发 杨村长 掘金小册核心知识 工程架构 全栈进阶 项目实战 快速精通 Nuxt3 开发 Nuxt 3 0 全栈开发 由杨村长撰写 299人购买https s juejin cn ds S6p7MVo 上一讲我们学习了
  • elementui 集成富文本编辑器vue-quill-editor

    第一步 安装vue quill editor cnpm install vue quill editor S 第二步 VUE项目集成vue quill editor main js 文件 添加如下代码片段 import VueQuillEd
  • 概率论 方差公式_考研冲刺篇

    众所周知 概率论的知识点又多又杂 需要我们系统的归类并掌握 这样才能获得得分 为此 小业整理了 2020考研数学 概率论各章节知识点梳理 的相关内容 希望对大家有所帮助 第一部分 随机事件和概率 1 样本空间与随机事件 2 概率的定义与性质
  • keil5打开MDK4的程序提示不兼容

    1 如下图 我的程序是用keil4写的 可是用keil5打开会提示不兼容的问题 keil提供了两个解决方案 Migrate to Device Pack 迁移到设备包 和 Install Legacy Support 安装遗留支持 用第二种
  • [数值计算-18]:最小二乘的求解法3 - 链式求导与梯度下降法求解loss函数的最优化参数(Python, 超详细、可视化)

    作者主页 文火冰糖的硅基工坊 https blog csdn net HiWangWenBing 本文网址 https blog csdn net HiWangWenBing article details 119978818 目录 前置文
  • 4.4创建型模式————抽象工厂模式

    前面介绍的工厂方法模式中考虑的是一类产品的生产 如畜牧场只养动物 电视机厂只生产电视机 计算机软件学院只培养计算机软件专业的学生等 同种类称为同等级 也就是说 工厂方法模式只考虑生产同等级的产品 但是在现实生活中许多工厂是综合型的工厂 能生