设计模式---抽象工厂(AbstractFactory)模式

2023-11-16

1 名词解释

产品等级:指产品的类型一样,品牌不一样。例如空调是一种产品类型,美的空调与格力空调是不同的品牌。

产品族:同一个品牌的不同产品。例如美的的空调,电饭锅,热水器属于同一产品族。

这里引用一个图片来具体说明这两个名词解释。(来自引用2)

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

2 定义

是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。

3 三种工厂的方法的区别

首先挂两个链接,一个是我写的简单工厂模式的链接,一个是工厂方法模式的链接。

简单工厂模式中工厂类包含了必要的逻辑,工厂类依据逻辑判断从而产生不同的类实例。但要加一个类实例的创建,我们需要修改简单工厂类的代码,增加逻辑判断,相当于我们开放了功能的扩展,又开放了代码的修改,违背的开闭原则。

工厂方法模式把逻辑判断转移到客户端中,在客户端中选择不同的工厂得到实例化对象。我们需要添加一个实例化对象的创建时,只需要增加一个继承创建实例化对象工厂接口的类。

工厂方法模式的缺点在于会增加很多类,如果有很多实例化对象,每个对象都需要一个工厂类来专门创建对应的对象,造成类的数量很多,增加管理难度。

简单工厂模式与工厂方法模式都只能创建同一等级的产品,比如空调工厂只能生产空调,不能生产电视机,而抽象工厂模式能创建产品族,比如小米的工厂既能创建小米空调,又能创建小米电视,还能创建小米投影仪。

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

1.系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。

2.系统一次只可能消费其中某一族产品,即同族的产品一起使用。

4 优缺点

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

1.可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。

2.当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。

3.抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。


其缺点是:

1.当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。例如定义工厂能生产电视,空调。小米工厂与美的工厂继承抽象工厂都能生产电视和空调,现在工厂添加一个功能生产电饭煲,那小米工厂与美的工厂都需要修改。

5 结构与实现

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

1.抽象工厂(Abstract Factory):提供了创建产品的接口,它包含多个创建产品的方法 newProduct(),可以创建多个不同等级的产品。

2.具体工厂(Concrete Factory):主要是实现抽象工厂中的多个抽象方法,完成具体产品的创建。

3.抽象产品(Product):定义了产品的规范,描述了产品的主要特性和功能,抽象工厂模式有多个抽象产品。

4.具体产品(ConcreteProduct):实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间是多对一的关系。

如下图所示:(来自引用2)

6 代码示例

业务逻辑与简单工厂模式相同。业务需求是审核公司线上商城每一笔订单的用户评论和商户评论(对用户评论的一个回复),因为两种评论的模型有一些属性的不同,用户评论对应一个实体(UserComment)一张数据表(user_comment),商户回应评论对应一个实体(MerchantComment)一张数据表(merchant_comment)。两个实体,两张数据表,对应两个mapper(持久层框架用的Mybatis Plus)。现在前端调用接口对评论进行审核,返回审核的结果,审核结果中有一个参数(identity)标识是审核用户评论还是审核商户评论,依据identity的值在service层调用不同的mapper对数据进行持久化存储。

本例的抽象工厂既能创建mapper,也能创建comment,不同的产品等级。

6.1 抽象的评论 CommonComment

**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:28
 **/
@Data
public class CommonComment {

    private Integer id;

    private String commentContent;

    private String commentResult;
}

6.2 商户评论 MerchantComment

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:29
 **/
@Data
public class MerchantComment extends CommonComment {

    private String merchantName;
}

6.3 用户评论 UserComment

**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:29
 **/
@Data
public class UserComment extends CommonComment {

    private String userName;
}

6.4 抽象mapper接口 Mapper

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:24
 **/
public interface Mapper<T> {

    /**
     * 存储实体到数据库
     *
     * @param entity 存储的实体
     */
    void saveEntity(T entity);
}

6.5 商户品论mapper MerchantCommentMapper

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:26
 **/
public class MerchantCommentMapper implements Mapper<MerchantComment> {

    @Override
    public void saveEntity(MerchantComment merchantComment) {
        System.out.println("存储的是审核商户回复内容," + merchantComment.getMerchantName());
    }
}

6.6 用户评论mapper

**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-01 16:26
 **/
public class UserCommentMapper implements Mapper<UserComment> {

    @Override
    public void saveEntity(UserComment userComment) {
        System.out.println("存储的是审核用户评论内容," + userComment.getUserName());
    }
}

6.7 抽象工厂 MyAbstractFactory

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-28 11:37
 **/
public interface MyAbstractFactory {
    /**
     * 创建mapper实例
     * @return mapper实例
     */
    Mapper createMapperInstance();

    /**
     * 创建评论实例
     * @return 评论实例
     */
    CommonComment createCommentInstance();

}

6.8 生产商户产品的具体工厂 MerchantCommentConcreteFactory

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-29 11:08
 **/
public class MerchantCommentConcreteFactory implements MyAbstractFactory{

    @Override
    public Mapper createMapperInstance() {
        return new MerchantCommentMapper();
    }

    @Override
    public CommonComment createCommentInstance() {
        MerchantComment merchantComment = new MerchantComment();
        merchantComment.setId(1);
        merchantComment.setCommentContent("商户评论类容");
        merchantComment.setCommentResult("商户评论审核结果");
        merchantComment.setMerchantName("hello,我是商户评论");
        return merchantComment;
    }
}

6.9 生产用户产品的具体工厂 UserCommentConcreteFactory

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-29 11:08
 **/
public class UserCommentConcreteFactory implements MyAbstractFactory{
    @Override
    public Mapper createMapperInstance() {
        return new UserCommentMapper();
    }

    @Override
    public CommonComment createCommentInstance() {
        UserComment userComment = new UserComment();
        userComment.setId(1);
        userComment.setCommentContent("用户评论类容");
        userComment.setCommentResult("用户评论审核结果");
        userComment.setUserName("hello,我是用户评论");
        return userComment;
    }
}

6.10 主函数

/**
 * @program: design-pattern-learning
 * @author: zgr
 * @create: 2021-09-23 10:51
 **/
public class MainClass {

    public static void main(String[] args) {
        boolean flag = true;
        while (flag) {
            //模拟接口参数
            Scanner sc = new Scanner(System.in);
            String identity = sc.nextLine();
            if (identity.equals("exit")) {
                System.out.println("退出系统");
                flag = false;
            } else {
                if (identity.equals("user")) {
                    MyAbstractFactory factory = new UserCommentConcreteFactory();
                    Mapper mapper = factory.createMapperInstance();
                    mapper.saveEntity(factory.createCommentInstance());
                }else if (identity.equals("merchant")) {
                    MyAbstractFactory factory = new MerchantCommentConcreteFactory();
                    Mapper mapper = factory.createMapperInstance();
                    mapper.saveEntity(factory.createCommentInstance());
                } else {
                    System.out.println("身份标识参数输入错误");
                    continue;
                }
            }
        }
    }
}

6.11 运行结果

7 引用 

1.《大话设计模式》

2.抽象工厂模式(详解版)

8 源代码

design-pattern-learning/src/com/hz/design/pattern/abstracted/factory at main · airhonor/design-pattern-learning · GitHub

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

设计模式---抽象工厂(AbstractFactory)模式 的相关文章

  • JFrame 图标在 Ubuntu 12.04 中不显示

    我使用一些图像图标开发了一个 Swing 应用程序 应用程序 jar 文件在 Windows 中按预期工作 但相同的 jar 文件在 Ubuntu 12 04 操作系统上不显示框架的图像图标 我的示例代码 ImageIcon ImageIc
  • 如何从二维数组中仅打印单个列?

    我正在编写这个程序 我必须只打印二维数组的一列 而不是两者 for int i 0 i lt sjf length i for int j 0 j lt sjf i length j System out printf 5d 4s sjf
  • @Nullable 和 SonarQube “有条件执行的块应该可达”警告

    包有以下package info java ParametersAreNonnullByDefault package foo import javax annotation ParametersAreNonnullByDefault 类有
  • JaxB2Marshaller 未将 XML 绑定到 Kotlin 数据类

    我正在编写一个批处理作业来解析 XML 提取字段并将它们保存在数据库中 解析 XML 时 它会选取 2 个根元素 但将所有字段保留为空 因此在我的数据库中 我有 2 条记录将为空字段 似乎无法弄清楚为什么它无法读取元素 TIA Bean f
  • Jersey 客户端异步 POST 请求不等待响应

    我创建了一个简单的 Jersey 客户端 它能够成功地使用有效负载执行 POST 请求 但现在它正在等待来自 http 端点的响应 public void callEndpoint String endpoint String payloa
  • 原型 Bean 未按预期自动装配

    测试控制器 java RestController public class TestController Autowired private TestClass testClass RequestMapping value test me
  • 有没有办法在@Service上使用@ControllerAdvice

    我有一个项目需求 但我没有任何需求 Controller or RestController但我需要为我的服务层提供一个全局异常处理程序 所以我需要配置 ControllerAdvice on Service 请告诉我是否还有其他方法可以做
  • 从两个数组中查找公共文件

    我正在尝试从两个数组中查找通用名称文件 我已将两个不同文件夹的文件名保存在两个不同的数组中 现在我正在创建一个通用文件数组 其中包含具有通用名称的文件 filenames 1 包含文件夹 1 中文件名称的数组 filename2 包含文件夹
  • Java检测音频文件(mp3)

    我有这段代码可以读取 mp3 文件 import java io File import java io IOException import javax sound sampled AudioSystem import javax sou
  • 无法安装 JDK 9,因为“另一个 Java 安装正在进行中”

    我已经在 Windows 10 x64 上使用 JDK 9 一段时间了 但是当我去安装最新的早期版本 b174 时 我首先卸载了以前的版本 像往常一样 然后运行新的安装程序 它失败并显示一个消息框 显示 另一个 Java 安装正在进行中 您
  • egit:设置gitignore忽略所有eclipse项目文件

    我在 github 上有一个项目 我想从中删除所有与 eclipse 相关的文件 并允许克隆它的人使用他们想要的任何 ide 这是该项目 https github com vedi0boy Archipelo https github co
  • 为什么对象可以改变类变量的值?

    由甲骨文提供定义 http docs oracle com javase tutorial java javaOO classvars html 有时 您希望拥有所有对象共有的变量 这是通过 static 修饰符来完成的 声明中带有 sta
  • 错误:找不到符号 ArrayList

    我正在尝试创建某种列表来存储数组 表 中的值 我在这里使用数组列表 但我应该使用列表吗 但是 每次我尝试编译时 它都会引发以下错误 找不到标志 符号 ArrayList类 位置 玩家类 TablePlayer 代码如下 public cla
  • 从 Apache Kafka 中的主题删除消息

    所以我是 Apache Kafka 的新手 我正在尝试创建一个简单的应用程序 以便我可以更好地理解 API 我知道这个问题在这里被问了很多 但是如何清除存储在主题上的消息 记录 我看到的大多数答案都说要更改消息保留时间或删除并重新创建主题
  • Android 自定义相机 - 在矩形内裁剪图像

    我有一个自定义相机应用程序 它有一个居中的矩形视图 如下所示 当我拍照时 我想忽略矩形之外的所有内容 该视图与我的 XML 视图中的 Camera Preview 或 SurfaceView 没有任何联系 如下所示
  • 用 Java 编写“漂亮”代码的标准? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Android 调整图片大小

    我的图像存储在 SD 卡上 每个大小约为 4MB 我想调整每个的大小 而不是将其设置为 ImageView 但我不能使用BitmapFactory decodeFile path 因为异常 java lang OutOfMemoryErro
  • Java 需要一个 FileSet 包/类

    任何人都可以建议 Java 中的 FileSet 包 类吗 我所说的 FileSet 是指文件和目录的集合以及正则表达式支持的包含和排除规则 类似于 Apache Ant 谢谢 Apache 公共 IO文件工具 http commons a
  • 如何从项目文件夹中的 jlabel 上设置图像?

    我正在尝试制作一个 Java 桌面应用程序 我想设置一个图像JLabel 我正在使用 NetBeans 从我的项目文件夹中 我的目录结构是 F gt MARKET src lib src defaultpackage demo java i
  • 将菜单添加到空活动

    我在 Android Studio 中制作了一个 Android 应用程序 并想在其上创建一个选项菜单 我将其创建为一个空活动 现在意识到我最好创建一个空白活动来获取选项菜单 无论如何 是否可以在空活动中创建选项菜单 如果有人能给我指出一个

随机推荐

  • Linux/Unix 中的 AWK 命令

    AWK 适用于模式搜索和处理 该脚本运行以搜索一个或多个文件以识别匹配模式以及所述模式是否执行特定任务 在本指南中 我们将了解 AWK Linux 命令并了解它的功能 AWK 可以执行哪些操作 逐行扫描文件 将每个输入行拆分为字段 将输入行
  • 如何在 Python 中将字符串转换为日期时间或时间对象

    介绍 蟒蛇datetime and time模块均包括strptime 将字符串转换为对象的类方法 在本文中 您将使用strptime 将字符串转换为datetime and struct time 对象 将字符串转换为datetime对象
  • 如何在 Ubuntu 18.04 上使用 Python 3 设置 Jupyter Notebook

    介绍 Jupyter笔记本是一个开源 Web 应用程序 可让您创建和共享交互式代码 可视化等 该工具可与多种编程语言一起使用 包括 Python Julia R Haskell 和 Ruby 它通常用于处理数据 统计建模和机器学习 本教程将
  • 了解 Vue.js 生命周期挂钩

    介绍 生命周期挂钩是了解您正在使用的库如何在幕后工作的窗口 生命周期钩子允许您知道组件何时被创建 添加到 DOM 更新或销毁 本文将向您介绍 Vue js 中的创建 安装 更新和销毁钩子 先决条件 要完成本教程 您需要 熟悉 Vue js
  • Java 单例类中的线程安全

    Singleton 是最广泛使用的创建型设计模式之一 用于限制应用程序创建的对象 如果是在多线程环境中使用 那么单例类的线程安全性就非常重要 在现实应用程序中 数据库连接或企业信息系统 EIS 等资源是有限的 应明智地使用以避免任何资源紧缩
  • Fail2Ban 如何保护 Linux 服务器上的服务

    介绍 SSH 是连接云服务器的事实上的方法 它耐用且可扩展 随着新的加密标准的开发 它们可用于生成新的 SSH 密钥 确保核心协议保持安全 然而 没有任何协议或软件堆栈是完全万无一失的 SSH 在互联网上如此广泛的部署意味着它代表了一种非常
  • 如何在运行 Ubuntu 的 VPS 上安装和使用 Composer

    Status 已弃用 本文介绍不再受支持的 Ubuntu 版本 如果您当前运行的服务器运行 Ubuntu 12 04 我们强烈建议您升级或迁移到受支持的 Ubuntu 版本 升级到Ubuntu 14 04 从 Ubuntu 14 04 升级
  • 如何在 Rocky Linux 9 上安装 Node.js

    介绍 Node js是用于服务器端编程的 JavaScript 运行时 它允许开发人员使用 JavaScript 创建可扩展的后端功能 这是许多人在基于浏览器的 Web 开发中已经熟悉的语言 在本指南中 您将了解在 Rocky Linux
  • Java 堆空间与堆栈 - Java 中的内存分配

    不久前我写了几篇关于Java 垃圾收集 and Java 是按值传递 之后我收到了很多电子邮件来解释Java堆空间 Java堆栈内存 Java中的内存分配它们之间有什么区别 您会在 Java Java EE 书籍和教程中看到很多对堆和堆栈内
  • Spring WebFlux - Spring 响应式编程

    Spring WebFlux是Spring 5中引入的新模块 Spring WebFlux是Spring框架中向反应式编程模型迈出的第一步 Spring 响应式编程 如果您是反应式编程模型的新手 那么我强烈建议您阅读以下文章来了解反应式编程
  • 如何在 Ubuntu 16.04 上设置 Apache 虚拟主机

    介绍 Apache Web 服务器是在互联网上提供 Web 内容的最流行的方式 它占互联网上所有活跃网站的一半以上 并且非常强大和灵活 Apache 将其功能和组件分解为可以独立定制和配置的单独单元 描述单个站点或域的基本单位称为virtu
  • Android 倒计时器示例

    在这个 android 倒数计时器示例中 我们将实现一个计时器对象来显示进度进度条 我们将在本教程中构建的应用程序是测验应用程序中的一个有用组件 其中以图形方式显示完成该级别的剩余时间 以增强用户体验 Android 倒计时器 Androi
  • 如何在 Ubuntu 18.04 上设置私有 Docker 注册表

    作者选择了阿帕奇软件基金会接受捐赠作为为捐款而写程序 介绍 Docker 注册表是一个管理存储和交付 Docker 容器镜像的应用程序 注册表集中容器映像并减少开发人员的构建时间 Docker 镜像通过虚拟化保证相同的运行时环境 但构建镜像
  • C 编程中的 fgets() 和 gets()

    介绍 我们都熟悉scanf 功能 它是适用于获取基本用户输入的主要功能 虽然scanf 在接受诸如以下输入时效果很好整数 字符 浮点数等等 在获取包含空格的字符串输入时 它肯定会落后 让我们看一个例子 include
  • Spring Bean 范围

    Spring Bean Scopes 允许我们更精细地控制 bean 实例的创建 有时我们希望将 bean 实例创建为单例 但在其他一些情况下 我们可能希望在每次请求时或在会话中创建一次 Spring Bean 范围 有五种类型春豆 sco
  • 如何在 Ubuntu 20.04 上安装和使用 Docker

    介绍 Docker是一个应用程序 可简化管理应用程序进程的过程容器 容器允许您在资源隔离的进程中运行应用程序 它们与虚拟机类似 但容器更便携 更资源友好 并且更依赖于主机操作系统 有关 Docker 容器的不同组件的详细介绍 请查看Dock
  • 针对Spring/Gradle启动失败的一些通用解决方案

    文章目录 0 前言 1 更改Gradle JVM的Java JDK 1 1 执行JUnit测试时 Gradle报错 0 前言 当你对Spring Gradle启动失败的错误信息一筹莫展时 不妨试试以下这些通用的解决方案 1 更改Gradle
  • SpringBoot在普通类获取Service或者DAO

    1手动创建工具类 package com lhw locktest util import org springframework beans BeansException import org springframework contex
  • 编程每日一题_C程序设计_零钱兑换

    描述 来源 MOOC C语言程序设计 浙江大学 翁老师 有改编 给定人民币整元数值 如1元 5元 10元 100元 将该币值的钱全部兑换为零钱 一角 两角 五角 且每次兑换每种面值的零钱均出现 请给出兑换方案 输出一种兑换方案 代码1 in
  • 设计模式---抽象工厂(AbstractFactory)模式

    1 名词解释 产品等级 指产品的类型一样 品牌不一样 例如空调是一种产品类型 美的空调与格力空调是不同的品牌 产品族 同一个品牌的不同产品 例如美的的空调 电饭锅 热水器属于同一产品族 这里引用一个图片来具体说明这两个名词解释 来自引用2