Java与设计模式(3):抽象工厂模式

2023-11-08

一、定义

抽象工厂模式是一种创建型设计模式,它提供了一种将相关对象组合在一起创建的方式,而无需指定它们的具体类。

在抽象工厂模式中,有一个抽象工厂接口,该接口定义了一组创建相关对象的方法。每个具体的工厂类都实现了这个接口,并负责创建一组相关的对象。

抽象工厂模式的核心思想是将对象的创建与使用分离开来。客户端通过使用抽象工厂接口来创建对象,而不需要关心具体的对象是如何创建的。这样可以使客户端代码与具体对象的类解耦,提高代码的灵活性和可维护性。

二、Java示例

以下是一个简单的Java示例,演示了如何使用抽象工厂模式:

首先,定义抽象工厂接口 AbstractFactory

public interface AbstractFactory {
    ProductA createProductA();
    ProductB createProductB();
}

然后,实现具体的工厂类 ConcreteFactory,实现抽象工厂接口:

public class ConcreteFactory implements AbstractFactory {
    @Override
    public ProductA createProductA() {
        return new ConcreteProductA();
    }

    @Override
    public ProductB createProductB() {
        return new ConcreteProductB();
    }
}

接下来,定义产品接口 ProductAProductB

public interface ProductA {
    void operationA();
}

public interface ProductB {
    void operationB();
}

然后,实现具体的产品类 ConcreteProductAConcreteProductB

public class ConcreteProductA implements ProductA {
    @Override
    public void operationA() {
        System.out.println("ConcreteProductA operationA");
    }
}

public class ConcreteProductB implements ProductB {
    @Override
    public void operationB() {
        System.out.println("ConcreteProductB operationB");
    }
}

最后,在客户端中使用抽象工厂来创建对象:

public class Client {
    public static void main(String[] args) {
        AbstractFactory factory = new ConcreteFactory();
        
        ProductA productA = factory.createProductA();
        productA.operationA();
        
        ProductB productB = factory.createProductB();
        productB.operationB();
    }
}

在上述示例中,抽象工厂模式通过抽象工厂接口和具体的工厂类实现了对象的创建。客户端通过使用抽象工厂来创建产品对象,而不需要关心具体的产品是如何创建的。

三、优点

抽象工厂模式具有以下优点:

  1. 隔离具体类:抽象工厂模式将具体类的创建与使用分离开来。客户端只需要使用抽象工厂接口来创建对象,而不需要关心具体的类是如何创建的。这样可以降低客户端与具体类的耦合度,提高代码的灵活性和可维护性。

  2. 符合开闭原则:抽象工厂模式可以很方便地扩展新的产品族,只需要新增对应的具体工厂类和产品类即可,而不需要修改已有的代码。这符合开闭原则,即对扩展开放,对修改关闭。

  3. 提供一致性:抽象工厂模式确保了一组相关的产品对象被一起创建,保证了这些产品对象之间的一致性。客户端只需要使用抽象工厂来创建产品对象,无需关心具体的产品类,从而避免了产品之间不兼容或不一致的问题。

  4. 促进产品族的一致性:抽象工厂模式可以方便地创建一组相关的产品对象,保证了这些产品对象之间的一致性。这对于需要创建一系列相关产品的系统非常有用,例如创建不同操作系统下的界面组件。

  5. 可以在运行时动态切换:由于抽象工厂模式使用了接口和多态性,因此可以在运行时动态切换具体的工厂类,从而实现不同的创建逻辑。这种灵活性可以根据不同的需求来选择不同的具体工厂类。

总结起来,抽象工厂模式通过隔离具体类的创建与使用,提供了一种灵活、可扩展的方式来创建一组相关的产品对象。它具有良好的封装性,符合开闭原则,并且可以保证产品之间的一致性。

四、缺点

抽象工厂模式的一些缺点包括:

  1. 增加新产品族困难:抽象工厂模式在设计初期需要确定产品族的结构,一旦确定后,增加新的产品族就会变得困难。因为需要修改抽象工厂接口及其所有的具体工厂类,这可能会导致较大的代码修改。

  2. 增加新产品等级结构困难:与增加新产品族类似,如果需要增加新的产品等级结构,也会面临类似的困难。需要修改抽象工厂接口及其所有的具体工厂类,可能会导致较大的代码修改。

  3. 代码复杂性增加:抽象工厂模式引入了多个抽象类和接口,增加了代码的复杂性。在一些简单的情况下,使用抽象工厂模式可能会显得过于繁琐,不利于代码的理解和维护。

  4. 灵活性受限:抽象工厂模式在设计时需要确定产品族的结构,这限制了灵活性。如果需要动态地添加或替换产品,可能需要修改抽象工厂接口及其所有的具体工厂类,这可能会导致较大的代码修改。

  5. 不易扩展新的产品:如果需要增加新的产品,除了新增产品类外,还需要修改抽象工厂接口及其所有的具体工厂类。这可能会导致类的数量增加,使得系统变得更加复杂。

综上所述,抽象工厂模式虽然具有一些优点,但也存在一些缺点。在使用抽象工厂模式时,需要权衡其优缺点,并根据具体的需求来决定是否使用该模式。

五、使用场景

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

  1. 需要创建一组相关的产品对象:如果系统需要创建一组相关的产品对象,而这些产品对象之间有一定的关联或约束关系,可以使用抽象工厂模式来统一管理它们的创建。

  2. 需要在运行时动态切换产品族:如果系统需要在运行时根据不同的需求切换不同的产品族,可以使用抽象工厂模式。通过切换具体的工厂类,可以实现不同产品族的创建逻辑,而不需要修改客户端代码。

  3. 需要提供一组相关的产品类库:如果系统需要提供一个产品类库,而不希望暴露具体的实现细节,可以使用抽象工厂模式。通过抽象工厂接口,可以将产品的创建过程封装起来,只暴露抽象的接口给客户端使用。

  4. 需要实现产品等级结构:如果系统需要实现多个产品等级结构,即存在多个产品族和产品等级的组合,可以使用抽象工厂模式。通过抽象工厂接口和具体工厂类的组合,可以方便地创建不同产品族和产品等级的对象。

  5. 需要实现代码的解耦和灵活性:如果系统需要实现对象的创建与使用的解耦,以提高代码的灵活性和可维护性,可以使用抽象工厂模式。通过抽象工厂接口和具体工厂类的组合,可以将对象的创建过程与具体的类解耦,使得客户端代码更加灵活。

在使用抽象工厂模式时,需要权衡其优缺点,并根据具体的需求来决定是否使用该模式。同时,还需要遵循设计原则,确保抽象工厂模式能够带来更好的设计和扩展性。

六、注意事项

在使用抽象工厂模式时,需要注意以下几点:

  1. 抽象工厂的设计:在设计抽象工厂时,需要考虑产品族的结构和产品等级的结构,以及它们之间的关联关系。合理的抽象工厂设计可以提高代码的可扩展性和可维护性。

  2. 遵循开闭原则:抽象工厂模式应该遵循开闭原则,即对扩展开放,对修改关闭。在新增产品族或产品等级时,应该通过新增具体工厂类和产品类来实现,而不是修改已有的代码。

  3. 灵活性与复杂性的权衡:抽象工厂模式可以提供灵活性,但也会增加代码的复杂性。在使用该模式时,需要权衡灵活性和代码复杂性之间的关系,并根据具体的需求来决定是否使用该模式。

  4. 与单一职责原则的结合:抽象工厂模式应该遵循单一职责原则,即每个具体工厂类只负责创建一组相关的产品对象。如果一个具体工厂类负责创建过多的产品对象,可能会导致职责不清晰、代码难以维护。

  5. 具体工厂的选择:在使用抽象工厂模式时,需要选择合适的具体工厂类来创建产品对象。具体工厂类应该根据实际需求和配置来选择,以确保创建出符合要求的产品对象。

  6. 与依赖注入的结合:抽象工厂模式可以与依赖注入(DI)结合使用,通过依赖注入来动态地注入具体工厂类。这样可以进一步提高代码的灵活性和可测试性。

七、在spring 中的应用

在Spring框架的源码中,抽象工厂模式被广泛应用于各个模块和功能中。以下是一些常见的示例:

  1. BeanFactory接口:BeanFactory是Spring框架中的核心接口之一,它定义了创建和管理Bean对象的方法。BeanFactory接口可以被看作是一个抽象工厂,定义了创建和获取Bean对象的规范。具体的BeanFactory实现类,如DefaultListableBeanFactory,就相当于具体工厂类,负责创建和管理具体的Bean对象。

  2. ApplicationContext接口:ApplicationContext是BeanFactory接口的子接口,它提供了更多的功能和扩展,如国际化支持、事件发布等。ApplicationContext接口也可以被看作是一个抽象工厂,负责创建和管理Bean对象,同时提供了更多的上下文支持。具体的ApplicationContext实现类,如ClassPathXmlApplicationContext,就相当于具体工厂类,负责创建和管理具体的Bean对象。

  3. FactoryBean接口:FactoryBean是Spring框架中的一个特殊接口,它充当了抽象工厂和具体产品的双重角色。FactoryBean接口定义了创建和管理某种类型的Bean对象的方法。具体的FactoryBean实现类,如JdbcTemplate,既是一个抽象工厂,负责创建和管理JdbcTemplate对象,同时又是一个具体产品,JdbcTemplate对象可以被其他组件使用。

  4. AOP相关功能:在Spring框架的AOP模块中,抽象工厂模式被用于创建和管理代理对象。通过配置切面、通知和目标对象等,Spring容器会动态地创建代理对象,并将其注入到需要的地方。这里的代理对象可以看作是具体产品,而动态代理的创建过程则可以看作是抽象工厂的实现。

这些只是Spring框架中抽象工厂模式的一些应用示例,实际上,在Spring的各个模块和功能中,抽象工厂模式都被广泛应用。它提供了一种灵活、可扩展和可维护的方式来创建和管理对象,并通过依赖注入的方式将其注入到其他组件中,实现了对象的解耦和灵活性。这也是Spring框架能够提供丰富功能和易于扩展的重要原因之一。

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

Java与设计模式(3):抽象工厂模式 的相关文章

  • JVisualVM/JConsole 中的 System.gc() 与 GC 按钮

    我目前正在测试处理 XML 模式的概念验证原型 并围绕一个非常消耗内存的树自动机外部库 我已经获得了源代码 构建 我想绘制 真实峰值 堆 随着模式大小的增加 不同运行的内存消耗 使用的指标符合我的目的并且不会影响问题 或者至少是它的合理近似
  • 不同类型的数组

    是否可以有一个包含两种不同类型数据的数组 我想要一个包含双精度型和字符串的数组 我尝试过 ArrayList
  • GWT - 如何组织项目以拥有多个网页以及它们之间的导航

    我是 GET 的新手 顺便说一句 它给我留下了深刻的印象 并且发现它对于像我这样熟悉 C NET 桌面技术并愿意编写 Web 应用程序的人来说非常有吸引力 我根据 GWT Eclipse 向导生成的示例启动了自己的项目 该项目生成带有面板的
  • 是否可以使用 Flying Saucer (XHTML-Renderer) 将 css 解析为类路径资源?

    我正在尝试将资源打包到 jar 中 但我无法让 Flying Saucer 在类路径上找到 css 我无法轻松构建 URL 来无缝解决此问题 https stackoverflow com questions 861500 url to l
  • 是否可以通过编程方式查找 logback 日志文件?

    自动附加日志文件以支持电子邮件会很有用 我可以以编程方式设置路径 如以编程方式设置 Logback Appender 路径 https stackoverflow com questions 3803184 setting logback
  • 如何检测 Java 字符串中的 unicode 字符?

    假设我有一个包含 的字符串 我如何找到所有这些 un icode 字符 我应该测试他们的代码吗 我该怎么做呢 例如 给定字符串 A X 我想将其转换为 AYXY 我想对其他 unicode 字符做同样的事情 并且我不想将它们存储在某种翻译映
  • 套接字的读写如何同步?

    我们创建一个套接字 在套接字的一侧有一个 服务器 在另一侧有一个 客户端 服务器和客户端都可以向套接字写入和读取 这是我的理解 我不明白以下事情 如果服务器从套接字读取数据 它在套接字中是否只看到客户端写入套接字的内容 我的意思是 如果服务
  • 使用 Guice 优化注册表

    你好 今天思考了一种优化 有一些疑问 语境 我正在使用 Guice 2 进行 Java 开发 在我的网络应用程序中 我有一个转换器注册表 可以即时转换为某种类型 转换器描述如下 public class StringToBoolean im
  • 从 GitHub 上托管的 Spring Cloud Config Server 访问存储库的身份验证问题

    我在 GitHub 上的存储库中托管配置 如果我将回购公开 一切都好 但如果我将其设为私有 我将面临 org eclipse jgit errors TransportException https github com my user m
  • 如何避免 ArrayIndexOutOfBoundsException 或 IndexOutOfBoundsException? [复制]

    这个问题在这里已经有答案了 如果你的问题是我得到了java lang ArrayIndexOutOfBoundsException在我的代码中 我不明白为什么会发生这种情况 这意味着什么以及如何避免它 这应该是最全面的典范 https me
  • 读取电子邮件的文本文件转换为 Javamail MimeMessage

    我有一个电子邮件原始来源的文本文件 直接从 gmail 复制 如果您单击 查看原始文件 您就会看到它 我想读入该文件并将其转换为 MimeMessage 如果您好奇为什么 我设置了 JavaMaildir 并且需要用电子邮件填充它的收件箱以
  • 使用 Mockito 模拟某些方法,但不模拟其他方法

    有没有办法使用 Mockito 模拟类中的某些方法 而不模拟其他方法 例如 在这个 诚然是人为的 Stock我想嘲笑的班级getPrice and getQuantity 返回值 如下面的测试片段所示 但我想要getValue 执行乘法 如
  • 流中的非终结符 forEach() ?

    有时 在处理 Java Stream 时 我发现自己需要一个非终端 forEach 来触发副作用但不终止处理 我怀疑我可以用 map item gt f item 之类的方法来做到这一点 其中方法 f 执行副作用并将项目返回到流中 但这似乎
  • QuerySyntaxException:无法找到类

    我正在使用 hql 生成 JunctionManagementListDto 类的实际 Java 对象 但我最终在控制台上出现以下异常 org hibernate hql internal ast QuerySyntaxException
  • Docker 和 Eureka 与 Spring Boot 无法注册客户端

    我有一个使用 Spring Boot Docker Compose Eureka 的非常简单的演示 我的服务器在端口 8671 上运行 具有以下应用程序属性 server port 8761 eureka instance prefer i
  • 返回 Java 8 中的通用函数接口

    我想写一种函数工厂 它应该是一个函数 以不同的策略作为参数调用一次 它应该返回一个函数 该函数根据参数选择其中一种策略 该参数将由谓词实现 嗯 最好看看condition3为了更好的理解 问题是 它没有编译 我认为因为编译器无法弄清楚函数式
  • JMenu 中的文本居中

    好吧 我一直在网上寻找有关此问题的帮助 但我尝试的任何方法似乎都不起作用 我想让所有菜单文本都集中在菜单按钮上 当我使用setHorizontalTextPosition JMenu CENTER 没有变化 事实上 无论我使用什么常量 菜单
  • Java Swing:需要一个高质量的带有复选框的开发 JTree

    我一直在寻找一个 Tree 实现 其中包含复选框 其中 当您选择一个节点时 树中的所有后继节点都会被自动选择 当您取消选择一个节点时 树中其所有后继节点都会自动取消选择 当已经选择了父节点 并且从其后继之一中删除了选择时 节点颜色将发生变化
  • Java中HashMap和ArrayList的区别?

    在爪哇 ArrayList and HashMap被用作集合 但我不明白我们应该在哪些情况下使用ArrayList以及使用时间HashMap 他们两者之间的主要区别是什么 您具体询问的是 ArrayList 和 HashMap 但我认为要完
  • 泛型、数组和 ClassCastException

    我想这里一定发生了一些我不知道的微妙事情 考虑以下 public class Foo

随机推荐

  • vue框架采用的模式:MVVM模式

    Vue 框架采用的模式是MVVM模式 响应式布局 MVVM模式 Model View ViewModel 与MVC模式相比 不再局限于数据单向绑定 而是能够实现数据双向绑定 同步刷新 原理 View层和Model层是通过ViewModel层
  • 【电路设计】肌电信号采集电路分析

    最近在开发肌电信号的采集 表面肌电信号是非常微弱的生物信号 正常人体表面肌电信号赋值为0 1 5mV 主要能量频段集中在10 150Hz 电路主要是根据原始信号 设计相应的放大电路 滤波电路 详细可以看这个链接
  • JAVA消息(第一篇)JMS 很重要!!!!包教包会!!不闹!!!下一篇-AMQP(wire-level protocol)

    如果看完 进入第二篇AMQP 首先大致讲一下 java 消息模块 消息 个人理解分为两种 1 同步消息 RPC调用 2 异步消息 本篇讲解部分 一 同步消息java提供了多种方案 最新比较常用的方式就是spring Http invoker
  • 关于vue使用recorder.js录音功能

    关于vue使用recorder js录音功能 1 引入外部js文件 import HZRecorder from utils HZRecorder js js文件内容 export function HZRecorder stream co
  • 资源变现小程序开通微信官方小商店教程

    前提条件非个人注册的小程序 登录小程序的微信公众后台 点击左侧菜单设置 gt 基本信息下面的 gt 服务类目 点击服务类目详情 点击添加类目 商家自营 gt 家用电器 添加好后 刷新浏览器 这个时候左侧菜单会看到交易组件 点击交易组件会看到
  • idea-代码格式化快捷键设置

    idea默认格式化快捷键是 Ctrl Alt L 有时会因其它软件快捷键的冲突导致失灵 设置方法如下 1 File gt Settings 2 Keymap gt Code 3 Code gt Reformat Code 4 右击Refor
  • openGL之API学习(七十四)opengl版本的历史沿革

    OpenGL源于SGI公司为其图形工作站开发的IRIS GL 在跨平台移植过程中发展成为OpenGL SGI在1992年7月发布1 0版 后成为工业标准 由成立于1992年的独立财团OpenGL Architecture Review Bo
  • rust换源

    在 HOME cargo 目录下建一个config文件 windows默认是C Users user name cargo config文件输入 source crates io registry https github com rust
  • 算法(二)

    目录 0 前言 1 海明码的使用 2 理解海明码需要明白的知识 a 奇偶校检法 b 异或运算 3 海明码的原理 a 海明码原理的概述 b 多个校检位的设计 c 校检位个数的计算 d 海明码的总结 4 举例 a 计算校检码的个数 b 计算每一
  • Unity编辑器 - 使用GL绘制控件

    Unity编辑器 使用GL绘制控件 控件较为复杂时 可能造成界面卡顿 在EditorGUI中也可以灵活使用GL绘制来提升性能 以绘制线段为例 using UnityEngine using UnityEditor public class
  • 【数据结构】树的基础知识及三种存储结构

    个人主页 阿然成长日记 点击可跳转 个人专栏 数据结构与算法 C语言进阶 不能则学 不知则问 耻于问人 决无长进 文章目录 一 树的概念与定义 二 树的有关名词 三 树的存储结构 1 双亲表示法 2 孩子表示法 3 孩子兄弟表示法 又叫二叉
  • c语言6种内部排序,数据结构6种内部排序算法的比较

    1 需求分析 1 输入数据的形式为 伪随机数产生程序产生 且每次输入数不少于100个 至少要用5组不同的输入数据 2 输出的形式为 输出关键字参加的比较次数和关键字的移动次数 关键字交换计为3次移动 的数据 3 程序能达到的功能 对起泡排序
  • docker 简单安装 redis

    1 redis的简单安装 1 1 docker 寻找 redis镜像 docker search redis 1 2 docker 拉取 redis镜像 docker pull redis 1 3 运行创建Redis 1 4 进入容器 1
  • SQL留存率问题

    什么是留存率 留存率 retention rate 通常用来衡量用户或客户的忠诚度和粘性 留存率指的是在特定时间段内 有多少人保持了对某个产品 服务 平台或应用程序的使用并继续付费或进行其他有价值的操作 通常情况下 留存率会作为一个百分比表
  • redis 连接数据库_如何连接到Redis数据库

    redis 连接数据库 介绍 Introduction Redis is an open source in memory key value data store Whether you ve installed Redis locall
  • Adblock Plus 下载

    作用 下载人数 全球超过5000万人都在使用adblock plus 这个chrome插件完全免费 能够屏蔽整个互联网广告的插件你见过吗 那就是Adblock Plus Adblock Plus牛在哪里 在谷歌开发者商店里面有4000万以上
  • 【SLAM】卡尔曼滤波(Kalman Filter)

    卡尔曼滤波 Kalman filter 一种利用线性系统状态方程 通过系统输入输出观测数据 对系统状态进行最优估计的算法 由于观测数据中包括系统中的噪声和干扰的影响 所以最优估计也可看作是滤波过程 卡尔曼滤波器的原理解释如下 首先 我们先要
  • 团队管理中的代码评审

    代码评审在软件项目管理中是经常组织的活动 通过代码评审的工作也确实给我们的团队带来很多的益处 简单谈谈代码评审的感受 你们的团队是否也在进行代码评审 Code Review 的相关工作呢 1 为什么要组织代码评审 组织代码评审其主要目的是保
  • uni-app跨端开发微信小程序之nodejs与后端通信并动态打包项目以适应多环境开发

    摘要 这篇文章主要的目的是分享一个可与后端接口通信的自动化脚本插件 实现不同环境下可打包成不同配置的微信小程序源码 全程靠命令行自动发起请求 修改配置文件 自动编译 解放双手不是梦 看官在阅读文章前可以思考这样一个场景 有一份代码需要支持本
  • Java与设计模式(3):抽象工厂模式

    一 定义 抽象工厂模式是一种创建型设计模式 它提供了一种将相关对象组合在一起创建的方式 而无需指定它们的具体类 在抽象工厂模式中 有一个抽象工厂接口 该接口定义了一组创建相关对象的方法 每个具体的工厂类都实现了这个接口 并负责创建一组相关的