设计模式之旅:工厂模式全方位解析

简介


设计模式中与工厂模式相关的主要有三种,它们分别是:

  1. 简单工厂模式(Simple Factory):这不是GoF(四人帮,设计模式的开创者)定义的标准模式,但被广泛认为是工厂模式的一种简化。它实际上是一个类(工厂类),用于创建其他类的实例。客户端不直接创建对象,而是通过工厂类进行创建,这样就隐藏了实例创建的细节。简单工厂模式实际上违背了开闭原则(对扩展开放,对修改关闭),因为每次增加新的产品类时,都需要修改工厂类。
  2. 工厂方法模式(Factory Method):这是一个真正的设计模式,是GoF所定义的。在工厂方法模式中,创建对象的任务被转移到了一个方法中,但这个方法不是由创建者类(也就是工厂类)直接调用的,而是在其子类中实现的,这样的设计允许系统在不修改现有客户端代码的情况下引入新的产品类。这个模式遵循了开闭原则,使得增加新的产品类时,只需添加新的具体工厂类即可。
  3. 抽象工厂模式(Abstract Factory):这是一种更为复杂和灵活的工厂模式。它提供了一个接口,用于创建一系列相关或相互依赖的对象,而无需指定它们具体的类。抽象工厂允许客户端使用抽象的接口来创建一组相关的产品,而不需要知道(或关心)产品的具体类型。这种模式非常适用于系统中产品类的家族很多,而且这些产品是以系列的方式提供的情况。

简单来说,简单工厂模式注重于创建单一产品,工厂方法模式允许类的扩展,通过子类来指定创建哪个对象,而抽象工厂模式则提供一个创建产品家族的接口,使得创建一系列相关或依赖对象的客户端不依赖于产品的具体类。每种模式都有其适用的场景和优缺点,选择哪种模式取决于你面临的问题和设计的需求。

一、简单工厂模式


简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,用于创建对象而不必暴露创建逻辑给客户端,并且通过使用一个共同的接口来指向新创建的对象。这种模式是工厂方法模式的一个特殊实现,但并不是一个真正的设计模式,更多的是一种编程习惯。

目的

简单工厂模式的主要目的是为了实现对象的创建与使用的分离。通过一个单独的工厂类来决定哪种产品类应当被实例化,这样可以减少系统的耦合度,增加系统的灵活性。

如何实现

简单工厂模式通常由三个角色组成:

  1. 工厂类(Factory):一个负责实现创建所有实例的方法,根据不同的参数返回不同类的实例。
  2. 抽象产品类(Product):所有具体产品类的父类,负责描述所有实例所共有的公共接口。
  3. 具体产品类(ConcreteProduct):工厂类所创建的对象类,它们都继承自抽象产品类。

示例

假设我们有一个软件,需要根据不同的文件类型(如文本文件、图像文件)来创建不同的视图来显示内容。我们可以使用简单工厂模式来设计这个功能。

首先,定义一个抽象产品类:

public abstract class FileView {public abstract void display();
}

然后,创建具体产品类:

public class TextView extends FileView {@Overridepublic void display() {System.out.println("Displaying text file");}
}public class ImageView extends FileView {@Overridepublic void display() {System.out.println("Displaying image file");}
}

接下来,创建工厂类:

public class FileViewFactory {// 使用 getFileView 方法获取类型的对象public static FileView getFileView(String fileType) {if (fileType == null) {return null;}if (fileType.equalsIgnoreCase("TEXT")) {return new TextView();} else if (fileType.equalsIgnoreCase("IMAGE")) {return new ImageView();}return null;}
}

最后,客户端代码可以这样使用工厂类:

public class FactoryDemo {public static void main(String[] args) {FileView fileView = FileViewFactory.getFileView("TEXT");fileView.display();fileView = FileViewFactory.getFileView("IMAGE");fileView.display();}
}

优点

  • 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建对象的责任,而仅仅"消费"产品。
  • 增加新的产品类时,只需要扩展工厂类即可,符合开闭原则(对扩展开放,对修改封闭)。

缺点

  • 工厂类的职责相对过重,增加新的产品时,需要修改工厂类的判断逻辑,违背了开闭原则。
  • 不易于扩展过于复杂的产品结构。如果产品的创建逻辑过于复杂,可能会导致工厂类变得非常庞大,难以维护。

简单工厂模式是理解工厂方法模式和抽象工厂模式的基础,它通过专门的工厂类将创建实例的任务和客户端使用分离,从而实现了系统的解耦和灵活性的提高。

二、工厂方法模式


工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个创建对象的接口,但让实例化的工作由其子类去完成。这样的设计模式使得一个类在不改变其代码的情况下增加新类型的产品。它是实现软件框架的一个重要方法,允许用户扩展框架中的部分功能,而无需修改框架的代码。

目的与应用场景

工厂方法模式主要用于以下情况:

  • 当一个类不知道它所必须创建的对象的类的时候。
  • 当一个类希望由它的子类来指定创建对象的时候。
  • 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪个帮助子类是代理者这一信息局部化的时候。

结构

工厂方法模式主要包含以下四个角色:

  1. 产品(Product):定义了工厂方法所创建的对象的接口,也就是实际产品共有的接口或抽象类。
  2. 具体产品(Concrete Product):实现或继承了产品接口的具体类,这些类将由具体工厂创建,它们之间是继承关系。
  3. 创建者(Creator):声明了工厂方法,该方法返回一个产品类型的对象。创建者也可以定义一个工厂方法的默认实现,返回一个默认的具体产品对象。
  4. 具体创建者(Concrete Creator):重写或实现创建者中的工厂方法,以返回一个具体产品实例。

实现步骤

  1. 定义产品接口:所有具体产品类都应该实现这个接口,以便工厂方法可以返回这些类的实例。
  2. 创建具体产品类:实现产品接口的具体类。
  3. 定义创建者类:包含抽象的工厂方法,该方法应该返回一个产品接口的对象。创建者类通常会包含依赖于抽象产品的代码,而这些产品是由其子类通过工厂方法创建的。
  4. 实现具体创建者:为工厂方法提供实现,创建并返回具体产品实例。

优点

  • 提高了系统的灵活性:因为工厂方法模式把具体产品的创建推迟到子类中,因此增加新的具体产品不需要修改现有类的代码,符合“开闭原则”。
  • 扩展性强:在增加产品时只需要增加具体产品类和对应的具体工厂类,无需修改现有系统,符合“单一职责原则”。

缺点

  • 可能导致类的个数增加:每增加一个具体产品类,就需要增加一个相应的具体工厂类,这会导致系统类的个数成倍增加,增加了系统的复杂度和管理难度。

示例

假设我们有一个日志记录器(Logger)的框架,日志记录器可以是文件日志记录器、数据库日志记录器或网络日志记录器等。在这个例子中,Logger就是产品,文件日志记录器、数据库日志记录器等就是具体产品,LoggerCreator是创建者,具体的文件日志记录器创建者、数据库日志记录器创建者等则是具体创建者。每个具体创建者都知道如何创建相应的具体产品。

工厂方法模式通过这种方式提供了一种将客户端代码从具体产品类中解耦的机制,使得增加新的产品类变得更加简单和灵活。下面是一个使用Java实现的工厂方法模式的简单例子,演示了如何构建一个简单的日志记录器框架。在这个框架中,我们有一个Logger接口,它定义了日志记录功能;有两种具体的日志记录器,分别是FileLoggerConsoleLogger;还有相应的工厂类,FileLoggerFactoryConsoleLoggerFactory,它们负责创建具体的日志记录器实例。

1. 定义产品接口

public interface Logger {void log(String message);
}

2. 创建具体产品类

文件日志记录器:

public class FileLogger implements Logger {@Overridepublic void log(String message) {// 实现将消息记录到文件的逻辑System.out.println("Logging to a file: " + message);}
}

控制台日志记录器:

public class ConsoleLogger implements Logger {@Overridepublic void log(String message) {// 实现在控制台输出日志的逻辑System.out.println("Logging to the console: " + message);}
}

3. 定义创建者(工厂)接口

public abstract class LoggerFactory {public abstract Logger createLogger();
}

4. 实现具体创建者

文件日志工厂:

public class FileLoggerFactory extends LoggerFactory {@Overridepublic Logger createLogger() {// 返回一个新的文件日志记录器对象return new FileLogger();}
}

控制台日志工厂:

public class ConsoleLoggerFactory extends LoggerFactory {@Overridepublic Logger createLogger() {// 返回一个新的控制台日志记录器对象return new ConsoleLogger();}
}

5. 客户端代码

public class FactoryMethodDemo {public static void main(String[] args) {LoggerFactory factory;Logger logger;// 创建文件日志记录器factory = new FileLoggerFactory();logger = factory.createLogger();logger.log("This is a message to the file logger.");// 创建控制台日志记录器factory = new ConsoleLoggerFactory();logger = factory.createLogger();logger.log("This is a message to the console logger.");}
}

在这个例子中,LoggerFactory充当创建者的角色,定义了一个抽象的createLogger方法,用于返回一个Logger对象。FileLoggerFactoryConsoleLoggerFactory是具体的创建者,它们实现了createLogger方法,分别用于创建FileLoggerConsoleLogger对象。这样,客户端代码就可以在不直接实例化日志记录器对象的情况下,通过工厂来获取日志记录器实例,从而实现了客户端代码和具体产品类之间的解耦。

三、抽象工厂模式


抽象工厂模式(Abstract Factory Pattern)是一种创建型设计模式,它提供了一种创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。这个模式的关键点是多个工厂类,这些工厂类负责创建一系列相关的对象。抽象工厂模式通常用于管理产品族的概念,并帮助构建组件库或框架。

抽象工厂模式的组成部分

  1. 抽象工厂(Abstract Factory):提供一个接口,用于创建相关的对象家族。
  2. 具体工厂(Concrete Factory):实现抽象工厂的接口,负责创建具体的产品实例。
  3. 抽象产品(Abstract Product):为一类产品对象声明一个接口。
  4. 具体产品(Concrete Product):实现抽象产品角色所定义的接口。

优点

  • 增加新的具体工厂和产品族很方便,无需修改已有的系统,符合开闭原则。
  • 隔离了具体类的生成,使客户端不需要知道什么被创建。

缺点

  • 添加新的产品对象到现有的工厂需要修改抽象工厂的接口,这将涉及到抽象工厂类以及所有的子类的修改,违反了开闭原则。

Java代码示例

假设我们有一个用于创建UI控件的框架,我们可以用抽象工厂模式来为不同的操作系统创建不同的UI控件。

首先,定义抽象工厂和抽象产品:

interface GUIFactory {Button createButton();Checkbox createCheckbox();
}interface Button {void paint();
}interface Checkbox {void paint();
}

然后,实现具体的工厂和产品:

class WinFactory implements GUIFactory {public Button createButton() {return new WinButton();}public Checkbox createCheckbox() {return new WinCheckbox();}
}class MacFactory implements GUIFactory {public Button createButton() {return new MacButton();}public Checkbox createCheckbox() {return new MacCheckbox();}
}class WinButton implements Button {public void paint() {System.out.println("Render a button in a Windows style.");}
}class MacButton implements Button {public void paint() {System.out.println("Render a button in a Mac style.");}
}class WinCheckbox implements Checkbox {public void paint() {System.out.println("Render a checkbox in a Windows style.");}
}class MacCheckbox implements Checkbox {public void paint() {System.out.println("Render a checkbox in a Mac style.");}
}

最后,客户端代码可以根据需要选择使用哪个具体的工厂实例:

class Application {private Button button;private Checkbox checkbox;public Application(GUIFactory factory) {button = factory.createButton();checkbox = factory.createCheckbox();}public void paint() {button.paint();checkbox.paint();}
}public class Demo {public static void main(String[] args) {Application app = new Application(new WinFactory());app.paint();}
}

这个示例展示了如何使用抽象工厂模式来解耦客户端和具体类的实例化过程,使客户端代码能够无需修改就可以使用不同的产品家族。

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

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

相关文章

【单片机家电产品学习记录--红外线】

单片机家电产品学习记录–红外线 红外手势驱动电路,(手势控制的LED灯) 原理 通过红外线对管,IC搭建的电路,实现灯模式转换。 手势控制灯模式转换,详细说明 转载 1《三色调光LED台灯电路》&#xff0c…

矩阵空间秩1矩阵小世界图

文章目录 1. 矩阵空间2. 微分方程3. 秩为1的矩阵4. 图 1. 矩阵空间 我们以3X3的矩阵空间 M 为例来说明相关情况。目前矩阵空间M中只关心两类计算,矩阵加法和矩阵数乘。 对称矩阵-子空间-有6个3X3的对称矩阵,所以为6维矩阵空间上三角矩阵-子空间-有6个3…

【Turtle】海龟先生

什么是编程 计算机只懂0和1这样的语言,可是我们不懂,当我们希望 计算要能帮我们做事情的时候,该怎么办呢? 我们需要一种更简便的方法告诉计算机要做什么,所以人类发明了编程语言 利用计算机编程语言,我们…

硬件了解 笔记

motherboard的高低端区别在哪里? 核心:从单核变成双核,多核(几核就是几个打工人) 多线程:6核本来对应6个线程,但是多线程就是说6核对应12个线程 频率 主频:平时打工的速度 睿频&…

iNeuOS工业互联网操作系统,“低代码”表单开发应用过程(一)

iNeuOS工业互联网操作系统,“低代码”表单开发应用过程(一) 目 录 1. 概述... 2 2. “低代码”表单开发应用过程... 2 1. 概述 iNeuOS工业互联网操作系统“表单设计”功能经过升级后,能够适用于更多应用场景&…

Altair® FluxMotor® 电机拓扑探索和多物理场优化

Altair FluxMotor 电机拓扑探索和多物理场优化 FluxMotor 致力于解决电机的整体设计问题。该软件工具可帮助工程师加快电机设计速度,在考虑多物理场约束条件的同时快速探究各种参数配置,并在几分钟内选出完善的可能。 FluxMotor 具有简单直观的使用界面…

美摄科技AI智能图像矫正解决方案

图像已经成为了企业传播信息、展示产品的重要媒介,在日常拍摄过程中,由于摄影技巧的限制和拍摄环境的复杂多变,许多企业面临着图像内容倾斜、构图效果不佳等挑战,这无疑给企业的形象展示和信息传递带来了不小的困扰。 美摄科技深…

Windows Edge浏览器兼容性问题诊断与修复策略详解

随着Microsoft Edge浏览器的持续迭代与更新,其性能与兼容性已得到了显著提升。然而,在面对互联网上纷繁复杂的网页内容时,仍有可能遇到兼容性问题。本文旨在探讨Edge浏览器在处理网页兼容性问题时的常见场景、原因分析及相应的解决方案&#…

索引下推(Index Condition Pushdown,简称 ICP)

Mysql可以分为Server层和存储引擎层 所以,最终进行I/O的是存储引擎对文件系统进行I/O操作 索引下推(Index Condition Pushdown,简称 ICP) 对应InnoDB,索引下推适用于非聚簇索引(二级索引)。 …

数据结构进阶篇 之【选择排序】详细讲解(选择排序,堆排序)

民以食为天,我以乐为先 嘴上来的嘘寒问暖,不如直接打笔巨款 一、选择排序 1.直接选择排序 SelectSort 1.1 基本思想 1.2 实现原理 1.3 代码实现 1.4 直接选择排序的特性总结 2.堆排序 HeapSort 跳转链接:数据结构 之 堆的应用 二、完…

26.活锁、饥饿锁

两个线程,相互改变了对方结束条件,导致两个线程不能结束。执行时间也都是一样,导致两个线程永远不会结束。 Slf4j public class LiveLockDemo {static volatile int count 10;public static void main(String[] args) {new Thread(() ->…

单片机中的RAM vs ROM

其实,单片机就是个小计算机。大计算机少不了的数据存储系统,单片机一样有,而且往往和CPU集成在一起,显得更加小巧灵活。 直到90年代初,国内容易得到的单片机是8031:不带存储器的芯片,要想工作&a…

FPGA高端项目:解码索尼IMX327 MIPI相机+图像缩放+视频拼接+HDMI输出,提供开发板+工程源码+技术支持

目录 1、前言免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX327 及其配置MIPI CSI RX图像 ISP 处理自研HLS图像缩放详解Video Mixer…

k8s小白的学习初体验

前言 有些时候的巧合让人匪夷所思,前两周刚刚尝试了一遍Docker操作,紧接着就收到好朋友说要学习k8s容器部署的建议,最近两周抽空看了一些关于k8s的知识,相关概念真的是太多了,概念本身是枯燥的,但是当概念…

Django详细教程(二) - 部门用户管理案例

文章目录 前言一、新建项目二、新建app三、设计表结构四、新建数据库五、新建静态文件六、部门管理1.部门展示2.部门添加3.部门删除4.部门编辑 七、模板继承八、用户管理1.辨析三种方法方法一:原始方法方法二:Form组件(简便)方法三:ModelForm…

Python | Leetcode Python题解之第8题字符串转换整数atoi

题目: 题解: INT_MAX 2 ** 31 - 1 INT_MIN -2 ** 31class Automaton:def __init__(self):self.state startself.sign 1self.ans 0self.table {start: [start, signed, in_number, end],signed: [end, end, in_number, end],in_number: [end, end,…

git源码泄露

Git 源码泄露 开发人员会使用 git 进行版本控制,对站点自动部署。但如果配置不当,可能会将 .git 文件夹直接部署到线上环境,这就引起了 git 泄露漏洞,我们可以利用这个漏洞直接获得网页源码。 确定是否存在泄漏 (1&…

C++相关概念和易错语法(2)(引用、内联函数、auto类型)

1.引用和指针的关系 引用在语法层面上不开辟新的空间,是对变量或别名取别名,我们对别名进行的任何操作也会同样作用于变量本身,这和形参有本质的区别,它的功能更像是指针。事实上,引用底层的实现就是指针,…

毅力流体设备现已加入2024年第13届生物发酵展

参展企业介绍 温州毅力流体设备有限公司位于浙江温州,这里海、陆、空交通网发达,地理位置优越。是一家经浙江-其他工商机关注册、依法经营的法人机构。 温州毅力流体设备有限公司所生产产品包括交通运输,船舶救生设备,空气呼吸器,等等,所生产…

【JS】监听元素重叠

常见场景: 滚动条滚动到底部时加载数据,如果监听滚动事件,会造成不必要的浪费。如频繁滚动但未达底部。可以建立观察者,监听loading标识元素到达视口某位置后再加载数据。 步骤 创建一个新的 IntersectionObserver 对象&#xf…