软件设计模式系列之三———工厂方法模式

1 模式的定义

工厂方法模式是一种常见的设计模式,属于创建型设计模式之一,它在软件工程中用于对象的创建。该模式的主要思想是将对象的创建过程抽象化,将具体对象的实例化延迟到子类中完成,以便在不同情况下可以创建不同类型的对象,而客户端代码不需要知道实际创建的对象类型。

2 举例说明

在这里插入图片描述

不同公司都生产自己的手机,就符合工厂方法模式。比如小米和华为都是手机制造商,而手机则是产品。每家公司都有自己的生产流程和标准,但它们都需要生产手机以满足市场需求。
工厂方法模式中,每家公司都有一个具体的工厂(小米工厂和华为工厂),这些工厂实现了一个共同的抽象工厂接口。抽象工厂定义了一个方法用于生产手机,但具体的手机生产过程由每家公司的工厂来实现。
客户端代码可以根据需要选择使用小米工厂或华为工厂来生产手机。这种方式下,客户端代码无需关心手机的具体制造过程,只需知道如何与抽象工厂交互即可。
工厂方法模式的优点在于它实现了对象的创建和客户端代码的解耦,使得不同的工厂可以独立扩展,适用于多样化的产品生产场景。小米和华为手机的制造就是一个生动的示例,其中工厂方法模式为不同公司的手机生产提供了一种灵活的、可扩展的解决方案

3 结构

工厂方法模式的结构包括以下几个关键角色:

在这里插入图片描述

  • 抽象工厂接口(Factory):这是工厂方法模式的核心部分,它定义了一个或多个工厂方法的接口,这些方法用于创建具体产品对象。通常,这个接口中会包含多个方法,每个方法用于创建不同类型的产品。客户端代码通过调用这些工厂方法来获取产品对象。
  • 具体工厂类(Concrete Factory):这是实现抽象工厂接口的具体类,每个具体工厂类负责创建一类具体产品。它实现了工厂方法,根据客户端的需求创建具体的产品对象。每个具体工厂类通常对应一个特定的产品族。
  • 抽象产品接口(Product):这个接口定义了产品对象的通用属性和方法,所有具体产品类都必须实现这个接口。客户端代码将与抽象产品接口进行交互,而不直接与具体产品类进行交互。
  • 具体产品类(Concrete Product):这些是实际的产品类,它们实现了抽象产品接口,定义了具体产品的属性和行为。每个具体产品类对应一个具体工厂类。
  • 客户端(Client):客户端代码需要创建产品对象,但它不直接与具体产品类或具体工厂类交互。客户端通过调用抽象工厂接口中的工厂方法来创建产品对象,从而实现了解耦的目的。

工厂方法模式的结构允许在不修改客户端代码的情况下引入新的具体产品类和具体工厂类,从而增加系统的可扩展性。客户端只需要知道抽象工厂接口和抽象产品接口,而不需要关心具体的产品类和工厂类,这使得系统更易于维护和扩展。

总结来说,工厂方法模式的结构包括抽象工厂接口、具体工厂类、抽象产品接口、具体产品类以及客户端。这个模式通过将对象的创建委托给具体工厂类来实现对象的创建和客户端与产品之间的解耦。

4 实现步骤

工厂方法模式的实现步骤通常包括以下几个关键步骤:

  • 定义抽象产品接口(Product):定义一个抽象产品接口,它声明了产品对象的通用属性和方法。所有具体产品类都必须实现这个接口。
  • 创建具体产品类(Concrete Product):实现抽象产品接口的具体产品类。每个具体产品类表示一种具体的产品。
  • 定义抽象工厂接口(Factory):创建一个抽象工厂接口,该接口声明了工厂方法,用于创建产品对象。
  • 创建具体工厂类(Concrete Factory):实现抽象工厂接口的具体工厂类,每个具体工厂类负责创建特定类型的产品。在客户端中使用工厂方法:
  • 客户端代码通过具体工厂类的工厂方法来创建产品对象,而不直接实例化具体产品类。

通过上述步骤,您就可以实现工厂方法模式。这种模式允许客户端根据需要选择合适的具体工厂来创建产品,从而实现了解耦和可扩展性。如果需要添加新的产品类型,只需创建新的具体产品类和对应的具体工厂类,而不需要修改现有的客户端代码。

5 代码实现

以下是使用工厂方法模式实现抽象工厂(AbstractFactory)、具体工厂(XiaomiFactoryHuaweiFactory)、抽象产品(AbstractMobile)和具体产品(XiaomiMobileHuaweiMobile)的Java代码示例:

// 抽象产品接口
interface AbstractMobile {void displayInfo();
}// 具体产品类 - 小米手机
class XiaomiMobile implements AbstractMobile {@Overridepublic void displayInfo() {System.out.println("这是小米手机。");}
}// 具体产品类 - 华为手机
class HuaweiMobile implements AbstractMobile {@Overridepublic void displayInfo() {System.out.println("这是华为手机。");}
}// 抽象工厂接口
interface AbstractFactory {AbstractMobile createMobile();
}// 具体工厂类 - 小米工厂
class XiaomiFactory implements AbstractFactory {@Overridepublic AbstractMobile createMobile() {return new XiaomiMobile();}
}// 具体工厂类 - 华为工厂
class HuaweiFactory implements AbstractFactory {@Overridepublic AbstractMobile createMobile() {return new HuaweiMobile();}
}// 客户端
public class Client {public static void main(String[] args) {// 使用具体工厂创建具体产品AbstractFactory xiaomiFactory = new XiaomiFactory();AbstractMobile xiaomiMobile = xiaomiFactory.createMobile();xiaomiMobile.displayInfo();AbstractFactory huaweiFactory = new HuaweiFactory();AbstractMobile huaweiMobile = huaweiFactory.createMobile();huaweiMobile.displayInfo();}
}

在这个代码示例中,我们定义了抽象产品接口 AbstractMobile 和两个具体产品类 XiaomiMobileHuaweiMobile。然后,我们定义了抽象工厂接口 AbstractFactory,其中包含了一个工厂方法 createMobile(),用于创建手机产品。

接下来,我们创建了两个具体工厂类 XiaomiFactoryHuaweiFactory,分别实现了 AbstractFactory 接口,并在其中实现了工厂方法,分别用于创建小米手机和华为手机。

最后,在客户端代码中,我们使用不同的具体工厂来创建不同的手机产品,从而实现了工厂方法模式,客户端代码不需要知道具体产品的细节,只需要知道如何使用抽象工厂来创建产品

6 典型应用场景

6.1 数据库驱动程序的创建

在这里插入图片描述

使用工厂方法模式来进行数据库驱动程序创建的场景是在软件开发中需要连接不同类型的数据库(例如MySQL、PostgreSQL、Oracle等)时。通过工厂方法模式,可以将不同数据库的连接对象的创建过程封装在各自的工厂类中,客户端代码无需关心具体的数据库驱动程序实现,只需使用相应的工厂来创建数据库连接对象,从而实现了灵活性和可扩展性,能够轻松地切换和添加新的数据库驱动程序,而不影响现有的代码。这种模式在多数据库支持和数据库连接的抽象化方面非常有用。

6.1 UI控件的创建

使用工厂方法模式进行UI控件创建的场景是在图形用户界面(GUI)开发中。不同操作系统或界面库(如Windows、macOS、Android等)可能使用不同的UI控件(如按钮)。通过工厂方法模式,可以将每种UI控件的创建过程封装在各自的工厂类中,客户端代码无需关心具体的控件实现,只需使用相应的工厂来创建控件对象,从而实现了跨平台和可扩展性,使得应用程序能够在不同的操作系统或界面库下创建合适的UI控件,而不需要重写整个界面代码。这种模式在多平台UI开发和UI组件的抽象化方面非常有用。

6.3 日志记录器

在应用程序中需要记录日志以进行调试、故障排除和性能监测时。不同的日志记录方式(如文件日志、数据库日志、控制台日志等)可能需要使用不同的日志记录器。通过工厂方法模式,可以将每种日志记录器的创建过程封装在各自的工厂类中,客户端代码无需关心具体的日志记录器实现,只需使用相应的工厂来创建日志记录器对象,从而实现了灵活性和可扩展性,使得应用程序可以根据需求选择不同的日志记录方式,而不需要修改主要的应用逻辑。这种模式在日志记录方式的切换和定制化日志记录方面非常有用。

6.4 游戏中不同角色的创建

使用工厂方法模式来创建游戏中不同角色的场景是在游戏开发中。在游戏中,有各种不同类型的角色(如玩家、敌人、道具、NPC等),每个角色都有自己独特的属性和行为。通过工厂方法模式,可以将每种角色的创建过程封装在各自的工厂类中,客户端代码无需关心具体的角色实现,只需使用相应的工厂来创建角色对象,从而实现了游戏角色的动态创建和管理。这种模式在游戏中角色的扩展和多样化方面非常有用,使得游戏开发人员可以轻松地添加新的角色类型,而不需要修改游戏引擎或核心逻辑。

7 优缺点

工厂方法模式是一种常用的设计模式,它具有一些优点和缺点:

优点:

松耦合 :工厂方法模式将对象的创建过程封装在工厂类中,客户端代码与具体产品类解耦。客户端代码只需要关心抽象工厂和产品接口,无需了解具体产品的细节。

可扩展性 :通过添加新的具体工厂类和具体产品类,可以轻松扩展系统以支持新的产品类型,而不需要修改现有的代码。这使得系统更容易维护和扩展。

多态性 :工厂方法模式利用了多态性,使得客户端可以根据需要创建不同类型的产品对象,而无需改变客户端代码。

符合开闭原则 :工厂方法模式遵循开闭原则,对修改关闭,对扩展开放。添加新的产品类型只需要添加新的具体工厂类和具体产品类,而不需要修改现有代码。

缺点:

类的数量增加 :引入工厂方法模式会增加类的数量,每个具体产品类都需要一个对应的具体工厂类。对于一些简单的情况,可能会使代码变得复杂。

复杂性增加 :在有多层继承结构的情况下,可能会引入更多的层次,增加代码的复杂性。

不适用于单例 :工厂方法模式通常用于创建多个对象,不适用于创建单例对象。对于单例模式,通常使用其他模式,如单例模式或者静态工厂方法。

增加代码复杂度 :在简单情况下,使用工厂方法模式可能会增加不必要的复杂性,不如直接实例化对象来得简单。

总之,工厂方法模式在实现对象的创建和客户端代码解耦方面有很多优点,但也需要谨慎使用,根据具体情况来决定是否使用该模式,以确保代码的可维护性和扩展性。

8 类似模式

工厂方法模式、抽象工厂模式和简单工厂模式都是创建型设计模式,用于对象的创建,但它们在关注点和应用场景上存在差异。

简单工厂模式是一种简化对象创建的方法,不是 GoF(Gang of Four)的正式设计模式。简单工厂适用于创建少量的对象,但不符合开闭原则,不支持扩展新的产品类型。

工厂方法模式是一种正式的设计模式,定义了一个创建对象的接口,具体的对象创建延迟到子类中完成。用于创建单一产品等级结构。

抽象工厂模式也是一种正式的设计模式,提供一个接口,用于创建一系列相关或依赖的对象,不需要指定具体的类。每个具体工厂类可以创建一组相关的产品,用于创建多个相关的产品等级结构或整个产品族。

它们都以不同的方式提供了对象创建的灵活性和可扩展性,根据需求选择合适的模式。

9 小结

工厂方法模式是一种常用的设计模式,属于创建型设计模式,其核心思想是将对象的创建延迟到子类中去完成。特别适合在需要创建多个相关但不同类型的对象时,以提高代码的可维护性和可扩展性。它将对象的创建过程进行了抽象,使得客户端代码更加灵活,可以根据需要选择不同的具体工厂来创建对象。

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

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

相关文章

yolov5训练ExDark数据集(附全过程代码,超详细教程,无坑!)

1.数据集获取 ExDark:免费下载地址 数据内容展示:共12个类别7363张 2.ExDark转yolo格式 ExDark的label文件内容 yolo的label文件内容 转换前准备如下 其中: anndir等于ExDark数据集中的Annotations文件夹,用于存放标签数据…

【LeetCode75】第五十四题 咒语和药水的成功对数

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 题目给我们两个数组,要我们找出第一个数组中每个元素能和另一个数组的元素匹配的数量。匹配的条件是乘积大于特定的值。 那么…

论文阅读《Robust Monocular Depth Estimation under Challenging Conditions》

论文地址:https://arxiv.org/pdf/2308.09711.pdf 源码地址:https://github.com/md4all/md4all 概述 现有SOTA的单目估计方法在理想的环境下能得到满意的结果,而在一些极端光照与天气的情况下往往会失效。针对模型在极端条件下的表现不佳问题&…

【软件测试】selenium3

自动化测试的概念 自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最 后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。 自动化测试就相当于将人工测试手段进行转换,让代码…

flex布局语法以及实操,一文带你吃透flex布局的基础

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一、Flex是什么? 二、Flex语法知识 1.轴的使用 1.1flex-direction属性 ​编辑 2.基础知识 2.1justify-content属性 2.1.1justify-content: fl…

【HTML5高级第二篇】WebWorker多线程、EventSource事件推送、History历史操作

文章目录 一、多线程1.1 概述1.2 体会多线程1.3 多线程中数据传递和接收 二、事件推送2.1 概述2.2 onmessage 事件 三、history 一、多线程 1.1 概述 前端JS默认按照单线程去执行,一段时间内只能执行一件事情。举个栗子:比方说古代攻城游戏&#xff0c…

CRM软件系统排名靠前的相关推荐

CRM软件是企业管理客户关系的重要工具,它可以帮助企业提高销售效率、增强客户满意度、提升市场竞争力。在众多的CRM软件中,排名靠前的CRM软件有哪些?推荐您一款领先的CRM软件——Zoho CRM。 Zoho CRM是一款全球知名的CRM软件,累计…

Ubuntu18.04系统下通过moveit控制kinova真实机械臂,并用python脚本到达固定点

测试工作空间:test_ws Kinova机械臂型号:m1n6s300 双臂模型中的左臂 测试功能包为kinova-ros官方包 一、读取kinova机械臂末端执行器位姿及tf小知识 1. tf小知识之获取两个连杆坐标系的位姿关系,非常有用,非常有用,非…

Linux tcpdump抓包命令

1.tcpdump抓包命令 -c 指定抓取包的数量,即最后显示的数量 -i 指定tcpdump监听的端口。未指定,选择系统中最小的以配置端口。-i any:监听所有网络端口 -i lo:监听lookback接口。-nn 对监听地址以数字方式呈现,且对端口也以数字方式呈现。…

Ubuntu 22.04安装过程

iso下载地址 Ubuntu Releases 1.进入引导菜单 选择Try or Install Ubuntu Server安装 2.选择安装语言 默认选择English 3.选择键盘布局 默认即可 4.选择安装服务器版本 最小化安装 5.配置网络 选择ipv4 选择自定义 DHCP也可 6.配置代理 有需要可以配置 这里跳过 7.软件源 …

LeetCode518. 零钱兑换 II 以及 动态规划相关的排列组合问题

文章目录 一、题目二、题解方法一:完全背包问题的变体(版本1)方法二:完全背包问题变体(版本2) 三、拓展:先遍历物品后遍历背包vs先遍历背包后遍历物品先遍历物品后遍历背包(组合问题…

高性能数据JS网格 Bryntum Grid 5.5.2 Crack

高性能数据网格 Bryntum Grid 是一个高性能的网络表格组件。它是用纯 JavaScript 构建的,并且可以轻松地与所有主要 JS 框架集成。 功能丰富 Bryntum Grid 具有您期望从专业网格组件获得的所有功能,包括: 很好的表现;很好的绩效 没有人喜欢缓…