Java二十三种设计模式-工厂方法模式(2/23)

工厂方法模式:设计模式中的瑞士军刀

引言

在软件开发中,工厂方法模式是一种常用的创建型设计模式,它用于处理对象的创建,将对象的实例化推迟到子类中进行。这种模式不仅简化了对象的创建过程,还提高了代码的可维护性和可扩展性。

基础知识,java设计模式总体来说设计模式分为三大类:

(1)创建型模式,共5种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。

(2)结构型模式,共7种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。

(3)行为型模式,共11种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

第一部分:工厂方法模式概述

1.1 工厂方法模式定义

工厂方法模式是一种创建型设计模式,用于将对象的创建过程封装在具体的工厂类中,而不是在客户端代码中直接创建。这种模式的目的是将对象创建的逻辑和使用逻辑分离,从而提高代码的可维护性和灵活性。

基本定义

工厂方法模式定义了一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method让类的实例化推迟到子类进行。

与简单工厂模式的区别

简单工厂模式使用一个中心化的工厂类来创建所有的对象,客户端代码直接与这个工厂类交互以获取所需的对象。这种方式虽然可以简化对象的创建过程,但随着产品种类的增加,工厂类的责任会变得越来越重,难以维护,且违反了开闭原则(对扩展开放,对修改封闭)。

工厂方法模式通过定义一个创建对象的接口,让具体的工厂类实现这个接口,从而为每个产品提供一个具体的工厂,这样新增产品种类时,只需要增加一个具体的工厂类,不需要修改已有代码,更好地遵循了开闭原则。

1.2 工厂方法模式组成

抽象产品(Product)

抽象产品是产品类的共同父类,定义了产品的接口。它是一个抽象角色,不实现具体的产品类。

具体产品(Concrete Product)

具体产品是抽象产品的子类,实现了抽象产品接口中定义的方法。在工厂方法模式中,具体产品由具体工厂类创建。

抽象工厂(Creator)

抽象工厂定义了创建对象的接口。它是一个抽象角色,不实现具体的创建方法。

具体工厂(Concrete Creator)

具体工厂是抽象工厂的子类,实现了抽象工厂中的创建方法。它负责实例化具体产品。

客户端(Client)

客户端代码使用抽象工厂来请求创建对象,客户端不直接与具体产品或具体工厂交互,而是通过抽象工厂与具体工厂进行交互。

通过这种分离,工厂方法模式提供了一种灵活的方式来管理对象的创建,使得新增产品种类时,不需要修改已有的客户端代码,只需要增加相应的具体工厂类即可。这种模式在实际开发中非常实用,尤其是在产品种类较多且经常变化的情况下。在下一部分中,我们将通过Java代码示例来展示工厂方法模式的具体实现。

第二部分:工厂方法模式实现

2.1 Java实现示例

以下是使用Java语言实现工厂方法模式的一个简单示例。我们将创建一个用于生成不同类型汽车的工厂。

// 抽象产品:汽车
interface Car {void assemble();
}// 具体产品:运动型汽车
class SportsCar implements Car {public void assemble() {System.out.println("Assembling a Sports Car.");}
}// 具体产品:豪华型汽车
class LuxuryCar implements Car {public void assemble() {System.out.println("Assembling a Luxury Car.");}
}// 抽象工厂:汽车工厂
interface CarFactory {Car createCar();
}// 具体工厂:运动型汽车工厂
class SportsCarFactory implements CarFactory {public Car createCar() {return new SportsCar();}
}// 具体工厂:豪华型汽车工厂
class LuxuryCarFactory implements CarFactory {public Car createCar() {return new LuxuryCar();}
}// 客户端代码
public class Client {public static void main(String[] args) {CarFactory factory = null;// 根据需求选择不同类型的汽车工厂factory = new SportsCarFactory();Car car = factory.createCar();car.assemble();factory = new LuxuryCarFactory();car = factory.createCar();car.assemble();}
}

2.2 模式中的角色和职责

抽象产品(Product)

  • 职责:定义一个产品接口,规范具体产品类应实现的行为。

具体产品(Concrete Product)

  • 职责:实现抽象产品接口的具体类,是工厂方法模式中被创建的对象。

抽象工厂(Creator)

  • 职责:声明一个创建产品的接口,不涉及具体类实例化。

具体工厂(Concrete Creator)

  • 职责
    • 实现抽象工厂的接口。
    • 具体实现创建产品的方法,生成具体产品对象。

客户端(Client)

  • 职责
    • 根据需求选择相应的具体工厂。
    • 通过具体工厂间接使用具体产品,实现了解耦。

在工厂方法模式中,客户端不直接与具体产品或具体工厂类交互,而是通过抽象工厂接口与具体工厂进行交互。这样做的好处是,当需要添加新的产品时,只需增加相应的具体工厂和具体产品类,而无需修改已有的客户端代码,从而遵循了开闭原则。这种模式提高了系统的灵活性和可扩展性,使得维护和扩展变得更加容易。在下一部分中,我们将讨论工厂方法模式的使用场景。

第三部分:工厂方法模式使用场景

3.1 产品族的扩展

当系统中存在一个产品族,且需要对产品族中的每个具体产品进行扩展时,工厂方法模式提供了一种非常合适的解决方案。

  • 产品族:指一组具有相同接口的产品,这些产品通常在功能上有一定的相似性,但又存在一些差异。
  • 应用场景:例如,在一个图形界面库中,可能存在多种不同类型的按钮(如圆形按钮、矩形按钮、带图标的按钮等)。这些按钮都属于按钮产品族,它们都实现了同一个按钮接口,但又各自有不同的实现。

工厂方法模式的应用:

  • 通过定义一个抽象工厂和工厂方法,可以为每个具体的产品提供一个对应的具体工厂。
  • 当需要扩展产品族时,只需增加相应的具体产品类和对应的具体工厂类,无需修改现有的工厂接口或其他工厂类。

3.2 依赖倒置原则

依赖倒置原则是面向对象设计原则之一,它要求高层模块不应依赖于低层模块,两者都应该依赖于抽象。

  • 实现方式:工厂方法模式通过使用抽象产品和抽象工厂,使得客户端代码依赖于抽象而不是具体实现。
  • 好处:这有助于降低模块间的耦合度,提高系统的灵活性和可维护性。

第四部分:工厂方法模式的优点与缺点

4.1 优点

封装性

工厂方法模式隐藏了对象创建的具体细节,客户端不需要知道具体是如何创建对象的。

扩展性

当需要添加新的产品时,只需增加相应的具体产品和工厂类,无需修改现有代码。

代码复用

通过使用工厂方法模式,可以在一个工厂类中创建多个相似对象,提高代码复用性。

4.2 缺点

增加系统复杂度

每增加一个产品类别,都需要增加一个具体类和产品类,这可能会导致系统中类的数量急剧增加。

增加系统的抽象性

在添加新的产品类时,需要对工厂方法的接口进行扩展,这可能会导致工厂方法的接口经常变化,增加了系统的抽象性。

不容易维护

当工厂方法模式的类数量逐渐增多时,可能会使系统难以理解和维护。

通过深入分析工厂方法模式的使用场景、优点和缺点,我们可以更明智地决定何时以及如何使用工厂方法模式。在实际开发中,我们应该根据具体需求和上下文来选择最合适的设计模式。在下一部分中,我们将比较工厂方法模式与其他设计模式,并提供一些最佳实践和建议。

第五部分:工厂方法模式与其他模式的比较

5.1 与抽象工厂模式的比较

工厂方法模式

  • 定义:用于创建一系列相关或依赖对象的接口,而不需要指定具体类。
  • 使用场景:当一个类不知道它所必须创建的对象的类时。

抽象工厂模式

  • 定义:创建一个工厂接口,用于创建一系列相关的或依赖的抽象产品。
  • 使用场景:当需要创建的产品族是相互关联的,并且希望它们能够一起被使用时。

不同点

  • 产品种类:工厂方法模式创建一个产品,而抽象工厂模式创建产品族。
  • 复杂性:抽象工厂模式通常比工厂方法模式复杂,因为它需要定义更多的接口和类。

5.2 与建造者模式的比较

工厂方法模式

  • 关注点:对象的创建,隐藏创建逻辑。
  • 适用情况:当创建过程只需要一个简单的步骤即可完成时。

建造者模式

  • 关注点:构建一个复杂对象,同时允许用户只通过指定复杂对象的类型和内容就能构建它们。
  • 适用情况:当创建过程需要多步骤或条件逻辑时。

差异

  • 复杂性:建造者模式适用于创建更复杂的对象,而工厂方法模式适用于简单的创建过程。
  • 灵活性:建造者模式提供了更多的灵活性,允许逐步构建对象。

第六部分:最佳实践和建议

6.1 使用工厂方法模式的最佳时机

  • 产品族扩展:当需要创建的产品属于同一类别,并且可能需要扩展时。
  • 依赖关系:当客户端不应该知道具体的产品类时,通过工厂方法模式可以降低客户端与具体产品的耦合。

6.2 避免滥用工厂方法模式

  • 过度使用:避免在不需要对象创建逻辑封装的情况下使用工厂方法模式,这可能导致不必要的复杂性。
  • 难以维护:随着产品种类的增加,管理大量的工厂类可能会变得困难。

6.3 替代方案

原型模式

  • 定义:使用原型实例指定创建对象的种类,并通过复制这些原型创建新的对象。
  • 适用场景:当创建新对象的成本较高时,或者需要通过复制现有的对象来快速创建新对象时。

依赖注入

  • 定义:通过外部注入依赖对象,而不是在类内部创建。
  • 好处:提高了代码的可测试性和灵活性。

服务定位器模式

  • 定义:当需要访问一个服务时,客户端会查询服务定位器以获取服务实例。
  • 适用场景:当系统中有大量的服务需要被访问,并且服务实例的创建和管理较为复杂时。

通过比较工厂方法模式与其他设计模式,我们可以更清晰地了解每种模式的适用场景和特点。在实际开发中,选择最合适的设计模式对于构建一个灵活、可维护的系统至关重要。同时,了解工厂方法模式的最佳实践和替代方案,可以帮助我们更好地应对不同的开发挑战。

结语

工厂方法模式是一种强大且灵活的设计模式,适用于多种不同的软件开发场景。通过本文的深入分析,希望读者能够对工厂方法模式有更全面的理解,并在实际开发中做出合理的设计选择。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/46314.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何预防最新的baxia变种勒索病毒感染您的计算机?

引言 在当今数字化时代,网络安全威胁层出不穷,其中勒索病毒已成为企业和个人面临的重大挑战之一。近期,.baxia勒索病毒以其高隐蔽性和破坏性引起了广泛关注。本文将详细介绍.baxia勒索病毒的特点、传播方式,并给出相应的应对策略…

QT VTK 简单测试工程

目录 1 目录结构 2 文件源码 3 运行结果 4 报错及处理 使用编译好的VTK库进行测试 1 目录结构 2 文件源码 Pro文件 QT core guigreaterThan(QT_MAJOR_VERSION, 4): QT widgetsCONFIG c17# You can make your code fail to compile if it uses deprecated APIs. #…

今天我们来聊Java IO模型,BIO、NIO、AIO三种常见IO模型

一、写在开头 很久没更新喽,最近build哥一直在忙着工作,忙着写小说,都忘记学习自己的本职了,哈哈,不过现在正式回归! 我们继续学习Java的IO相关内容,之前我们了解到,所谓的IO&#…

工作笔记 5 Post请求 密码加密器PasswordEncoder 小程序登录

1.微信小程序登录 1.1小程序登录流程图 1.2使用sa-token完成登录 参考csdn这位老哥的http://t.csdnimg.cn/oRgvI sa-token是一款轻量级的安全框架 1.2.1首先引入sa-token依赖 <dependency><groupId>cn.dev33</groupId><artifactId>sa-token-spring…

java日常开发中常用的集合工具类方法归总(java8 stream)

1、创建map集合的方式 方式1&#xff1a; Map<String, Object> map new HashMap<>(); map.put("a", "test"); map.put("b", "since"); 方式2&#xff1a; Map<String, Object> map2 new HashMap<>() {{…

【云原生】Prometheus整合Alertmanager告警规则使用详解

目录 一、前言 二、Altermanager概述 2.1 什么是Altermanager 2.2 Altermanager使用场景 三、Altermanager架构与原理 3.1 Altermanager使用步骤 3.2 Altermanager工作机制 3.3 Altermanager在Prometheus中的位置 四、Altermanager部署与接入Prometheus 4.1 Altermana…

ConfigMap-secrets-静态pod

一.ConfigMap 1.概述 ConfigMap资源&#xff0c;简称CM资源&#xff0c;它生成的键值对数据&#xff0c;存储在ETCD数据库中 应用场景&#xff1a;主要是对应用程序的配置 pod通过env变量引入ConfigMap&#xff0c;或者通过数据卷挂载volume的方式引入ConfigMap资源 官方解释…

UniVue@v1.4.0版本发布:运行时调试器RuntimeDebuger

GitHub仓库 发布版本仓库&#xff1a;https://github.com/Avalon712/UniVue 开发版本仓库&#xff1a;https://github.com/Avalon712/UniVue-Develop UniVue拓展框架UniVue源生成器仓库&#xff1a;https://github.com/Avalon712/UniVue-SourceGenerator 更新说明 在没有调…

【Python】Windows系统 pip 换源方法(永久 / 临时)

pip 换源 首先国内较好的镜像地址有&#xff1a; 清华&#xff1a;https://pypi.tuna.tsinghua.edu.cn/simple 阿里云&#xff1a;http://mirrors.aliyun.com/pypi/simple 豆瓣&#xff1a;http://pypi.douban.com/simple 腾讯&#xff1a;http://mirrors.cloud.tencent.com/…

Mysql数据表的约束(下)

3.默认值约束(default) 与非空约束的命令一致,因为都属于列级约束,因此只需将not null改为default 默认值即可 删除默认值约束: 4.主键约束(primary key) 表示给一张表格设置了一个唯一标识,为了更快的去通过唯一的数据去准确的查找到每一条记录,一半咱们在创建表…

【Linux】基于环形队列RingQueue的生产消费者模型

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 环形队列的概念及定义 POSIX信号量 RingQueue的实现方式 RingQueue.hpp的构建 Thread.hpp Main.cc主函数的编写 Task.hpp function包装器的使用 总结 前言…

关于Kafka Topic分区和Replication分配的策略

文章目录 1. Topic多分区2. 理想的策略3. 实际的策略4. 如何自定义策略 1. Topic多分区 如图&#xff0c;是一个多分区Topic在Kafka集群中可能得分配情况。 P0-RL代表分区0&#xff0c;Leader副本。 这个Topic是3分区2副本的配置。分区尽量均匀分在不同的Broker上&#xff0c…

第3章 创建最小(Minimal APIs)API应用程序

第1章 框架学习的基石与实战策略 第2章 大话ASP.NET Core 入门 第3章 创建最小&#xff08;Minimal APIs&#xff09;API应用程序 1.最小API概述 在ASP.NET Core的广阔天地里&#xff0c;"最小API应用程序"如同一把轻巧而强大的瑞士军刀&#xff0c;专为迅速构建…

idea中打开静态网页端口是63342而不是8080

问题&#xff1a; 安装了tomcat 并且也配置了环境&#xff0c;但是在tomcat下运行&#xff0c;总是在63342下面显示。这也就意味着&#xff0c;并没有运行到tomcat环境下。 找了好几个教程&#xff08;中间还去学习了maven&#xff0c;因为跟的教程里面&#xff0c;没有maven,但…

【 香橙派 AIpro评测】烧系统运行部署LLMS大模型体验Jupyter Lab AI 应用样例(新手入门)

文章目录 一、引言⭐1.1下载镜像烧系统⭐1.2开发板初始化系统配置远程登陆&#x1f496; 远程ssh&#x1f496;查看ubuntu桌面&#x1f496; 远程向日葵 二、部署LLMS大模型2.1 快速启动&#x1f496;拉取代码&#x1f496;下载mode数据&#x1f496;启动模型对话 三、体验 内置…

【算法笔记自学】第 10 章 提高篇(4)——图算法专题

10.1图的定义和相关术语 #include <cstdio>const int MAXN 100; int degree[MAXN] {0};int main() {int n, m, u, v;scanf("%d%d", &n, &m);for (int j 0; j < m; j) {scanf("%d%d", &u, &v);degree[u];degree[v];}for (int i…

自学鸿蒙HarmonyOS的ArkTS语言<九>自定义弹窗组件CustomDialog及二次封装自定义弹窗

一、自定义弹窗 CustomDialog struct CustomDialogBuilder {controller: CustomDialogController new CustomDialogController({ // 注意写法builder: CustomDialogBuilder({})})// controller: CustomDialogController // 这种预览会报错cancel?: () > voidconfirm?: (…

微信小游戏 彩色试管 倒水游戏 逻辑

最近开始研究微信小游戏&#xff0c;有兴趣的 可以关注一下 公众号&#xff0c; 记录一些心路历程和源代码。 定义一个 Cup类&#xff1a; 主要功能 初始化水杯&#xff1a;根据传入的颜色信息初始化水杯中的水层。 倒水&#xff1a;模拟水杯倾斜并倒出水的过程。 加水&…

Prometheus 云原生 - 基于 file_sd、http_sd 实现 Service Discovery

目录 开始 为什么需要服务发现机制 File Service Discovery&#xff08;file_sd&#xff09; 基本概念 配置方式 使用案例 HTTP Service Discovery&#xff08;http_sd&#xff09; 基本概念 配置方式 使用案例 开始 为什么需要服务发现机制 我们知道在 Prometheus …

【链表】算法题(一) ---- 力扣 / 牛客

一、移除链表元素 移除链表中值为val的元素&#xff0c;并返回新的头节点 思路&#xff1a; 题目上这样说&#xff0c;我们就可以创建一个新的链表&#xff0c;将值不为val的节点&#xff0c;尾插到新的链表当中&#xff0c;最后返回新链表的头节点。 typedef struct ListNo…