23种设计模式之工厂模式

文章目录

工厂模式

工厂模式是一种创建对象设计模式,将对象的创建和使用分离,可提高代码可维护性、可扩展性,封装复杂创建逻辑。其目的是隐藏对象创建的过程与细节。

在这里插入图片描述

工厂模式经典案例

国际化案例,根据用户的IP返回不同语言的界面。

在这里插入图片描述

工厂模式分类与优缺点

工厂模式主要分为三类:

一、简单工厂模式

简单工厂模式又称为静态工厂方法模式。它定义了一个创建对象的类,由这个类来封装实例化对象的行为。在简单工厂模式中,工厂类有一个创建产品对象的方法,这个方法可以根据传入的参数决定创建哪种具体的产品对象。

优点:实现了对象创建和使用的分离,客户端无需了解对象的具体创建过程,只需要关心如何使用对象。代码结构简单,容易理解和实现。

缺点:不符合开闭原则,即当需要增加新的产品对象时,需要修改工厂类的代码。

二、工厂方法模式

工厂方法模式是在简单工厂模式的基础上,将工厂类的创建方法抽象成抽象方法,由具体的工厂子类实现这些抽象方法来创建具体的产品对象。

优点:符合开闭原则,当需要增加新的产品对象时,只需要增加一个具体的工厂子类,无需修改原有代码。

缺点:工厂子类过多时,会导致代码结构复杂,增加系统的维护成本

三、抽象工厂模式

抽象工厂模式中,工厂类不再负责创建具体的产品对象,而是负责创建一系列相关的产品对象。客户端只需要调用抽象工厂的抽象创建方法,由具体的工厂子类来创建所需的产品对象系列。

优点:代码更加灵活和可维护,当需要增加新的产品对象系列时,只需要增加一个具体的工厂子类,无需修改原有代码。

缺点:实现复杂,不适合简单的应用场景。对开闭原则的支持也有一定的局限性,当需要增加新的产品对象种类时,需要修改抽象工厂和所有具体工厂的代码。

工厂模式的使用场景

基础使用:

  • 当对象创建涉及多步骤及依赖关系,工厂模式可封装复杂创建逻辑,让调用方代码更简洁。
  • 需根据不同条件创建不同类型对象,工厂模式能动态确定创建逻辑。
  • 期望统一管理对象创建以利维护和扩展,工厂模式可集中处理创建过程。

高级使用:

  • 与其他模式混用,如工厂模式与策略模式结合,或工厂模式、策略模式、模板模式共同使用。

工厂模式的优点

一、解耦

  • 工厂模式将对象的创建和使用分离,使得代码的各个部分之间的耦合度降低。使用者无需了解对象的具体创建过程,只需要从工厂获取所需的对象即可。这样,当对象的创建逻辑发生变化时,不会影响到使用对象的代码部分。
  • 例如,在一个电商系统中,订单模块需要使用支付对象进行支付操作。如果不使用工厂模式,订单模块可能直接实例化支付对象,这样订单模块就与具体的支付对象创建过程紧密耦合。当支付方式发生变化时,订单模块的代码需要进行相应的修改。而使用工厂模式,订单模块只需要从支付工厂获取支付对象,无需关心支付对象的具体创建过程,从而实现了解耦。

二、代码复用

  • 工厂类可以被多个地方复用,提高了代码的复用性。工厂类通常封装了对象的创建逻辑,可以根据不同的条件创建不同类型的对象。这些创建逻辑可以在多个地方重复使用,避免了代码的重复编写。
  • 例如,在一个图形绘制系统中,有多种不同类型的图形(圆形、矩形、三角形等)需要创建。可以创建一个图形工厂类,该工厂类可以根据不同的参数创建不同类型的图形对象。这样,在多个绘图模块中都可以复用这个图形工厂类,提高了代码的复用性。

三、符合迪米特法则和单一职责原则

  • 迪米特法则也称为最少知识原则,它强调一个对象应该对其他对象有尽可能少的了解。工厂模式将对象的创建逻辑封装在工厂类中,使用者只需要与工厂类进行交互,无需了解对象的具体创建过程,符合迪米特法则。
  • 单一职责原则要求一个类应该只有一个引起它变化的原因。工厂类的职责就是创建对象,它将对象的创建逻辑集中在一个地方,使得代码的职责更加清晰,符合单一职责原则。
  • 例如,在一个企业管理系统中,员工对象的创建可能涉及到从数据库中读取员工信息、验证员工数据的合法性等复杂的操作。如果将这些创建逻辑分散在各个使用员工对象的模块中,会导致代码的职责不清晰,违反单一职责原则。而使用工厂模式,将员工对象的创建逻辑封装在员工工厂类中,使得代码的职责更加清晰,符合单一职责原则。

简单工厂模式实现

以下是一个用于创建不同类型的手机。

一、定义手机产品接口

java">/*** 手机接口*/
public interface Phone {void call();void sendMessage();
}

二、创建具体手机产品类

java">/*** 安卓手机*/
public class AndroidPhone implements Phone {@Overridepublic void call() {System.out.println("Android手机正在通话。");}@Overridepublic void sendMessage() {System.out.println("Android手机正在发送消息。");}
}/*** 苹果手机*/
public class IPhone implements Phone {@Overridepublic void call() {System.out.println("iPhone正在通话。");}@Overridepublic void sendMessage() {System.out.println("iPhone正在发送消息。");}
}

三、创建简单工厂类

java">public class SimplePhoneFactory {/*** 根据传入的手机类型决定创建哪种具体的手机对象*/public static Phone createPhone(String phoneType) {if ("android".equals(phoneType)) {return new AndroidPhone();} else if ("iphone".equals(phoneType)) {return new IPhone();} else {return null;}}
}

四、使用简单工厂-测试

java">public class SimpleFactoryTest {public static void main(String[] args) {Phone androidPhone = SimplePhoneFactory.createPhone("android");if (androidPhone != null) {androidPhone.call();androidPhone.sendMessage();}System.out.println("--------------------------------");Phone iPhone = SimplePhoneFactory.createPhone("iphone");if (iPhone != null) {iPhone.call();iPhone.sendMessage();}}
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
--------------------------------
iPhone正在通话。
iPhone正在发送消息。

总结

简单工厂模式成功地实现了手机的创建与使用之间的解耦。这使得使用者无需操心手机具体的创建流程,仅需从工厂获取所需的手机即可。然而,此模式存有一定弊端。后续若要增添新的手机类型,就必须持续地对工厂类进行修改,如此一来,维护成本便会相对较高。在简单工厂模式里,需依据方法的输入,编写大量的 if-else 语句来判断并创建不同的对象。

工厂方法模式实现

工厂方法模式可视为简单工厂模式的升级版。它针对简单工厂模式在扩展时需改动工厂代码的缺点,对工厂类进行了优化改进。通过这种方式,工厂方法模式有效地解决了简单工厂模式在扩展性方面的不足。

例子还是使用上面的Phone,实现方法如下。

一、定义手机产品接口

代码和简单工厂模式一样。

二、创建具体手机产品类

代码和简单工厂模式一样。

三、定义抽象工厂接口

java">public interface PhoneFactory {Phone createPhone();
}

四、创建具体工厂类

java">public class AndroidPhoneFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new AndroidPhone();}
}public class IPhoneFactory implements PhoneFactory {@Overridepublic Phone createPhone() {return new IPhone();}
}

五、使用工厂方法模式

java">public class FactoryMethodTest {public static void main(String[] args) {PhoneFactory androidPhoneFactory = new AndroidPhoneFactory();Phone androidPhone = androidPhoneFactory.createPhone();androidPhone.call();androidPhone.sendMessage();System.out.println("--------------------------------");PhoneFactory iPhoneFactory = new IPhoneFactory();Phone iphone = iPhoneFactory.createPhone();iphone.call();iphone.sendMessage();}
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
--------------------------------
iPhone正在通话。
iPhone正在发送消息。

总结

其结果与简单工厂模式相同。二者的主要区别在于:简单工厂模式仅有一个工厂类,负责创建所有产品对象;而工厂方法模式则演变为多个工厂,每个工厂对应一种特定的产品创建。这样一来,后续扩展时只需实现工厂接口即可创建新的产品对象。然而,该模式的缺点是随着产品种类的增加,工厂类的数量也会越来越多。

抽象工厂模式实现

抽象工厂模式可视为工厂方法模式的一种扩展。该模式主要用于解决一类产品的创建问题。在抽象工厂模式中,工厂类的职责并非创建具体的单一产品对象,而是负责创建一系列相关的产品对象。例如,在某些场景下,工厂不仅要创建手机,还需创建与之对应的手机配件。对比工厂方法模式,最直观的区别在于工厂方法模式中的PhoneFactory接口通常只有一个创建手机的方法,而抽象工厂模式AbstractPhoneFactory接口则拥有多个方法,分别用于创建不同的相关产品对象。

下面是简单画的图。

在这里插入图片描述

一、定义手机产品接口

上面有代码。

二、创建具体手机产品类

上面有代码。

三、定义手机配件接口

java">public class AndroidCharger implements PhoneAccessory {@Overridepublic void describe() {System.out.println("安卓充电器。");}
}public class IPhoneCharger implements PhoneAccessory {@Overridepublic void describe() {System.out.println("苹果充电器。");}
}

五、定义抽象工厂接口

java">public interface AbstractPhoneFactory {/*** 创建手机*/Phone createPhone();/*** 创建配件*/PhoneAccessory createAccessory();
}

六、创建具体工厂类

java">public class AndroidFactory implements AbstractPhoneFactory {@Overridepublic Phone createPhone() {return new AndroidPhone();}@Overridepublic PhoneAccessory createAccessory() {return new AndroidCharger();}
}public class IPhoneFactory implements AbstractPhoneFactory {@Overridepublic Phone createPhone() {return new IPhone();}@Overridepublic PhoneAccessory createAccessory() {return new IPhoneCharger();}
}

七、使用抽象工厂模式

java">public class AbstractFactoryTest {public static void main(String[] args) {AbstractPhoneFactory androidFactory = new AndroidFactory();Phone android = androidFactory.createPhone();PhoneAccessory androidAccessory = androidFactory.createAccessory();android.call();android.sendMessage();androidAccessory.describe();System.out.println("----------------------------------");AbstractPhoneFactory iPhoneFactory = new IPhoneFactory();Phone iphone = iPhoneFactory.createPhone();PhoneAccessory iphoneAccessory = iPhoneFactory.createAccessory();iphone.call();iphone.sendMessage();iphoneAccessory.describe();}
}

执行结果

Android手机正在通话。
Android手机正在发送消息。
安卓充电器。
----------------------------------
iPhone正在通话。
iPhone正在发送消息。
苹果充电器。

总结

抽象工厂模式中,可存在多个方法用于创建同品类的不同对象。然而,该模式存在一定的缺点,即当需要增加新的品类时,需要对所有的具体工厂实现类进行修改。例如,若在抽象工厂接口AbstractFactory中新增一个方法B,那么AndroidFactoryIPhoneFactory等具体工厂类都需要实现这个新增的方法B

抽象工厂模式中,可以将上述示例中的工厂替换为工作中实际会用到的对象,例如对象存储服务(OSS)。以下展示的仅仅是两个 OSS 工厂,而在实际应用中,可能需要对接众多的 OSS 服务提供商,以满足不同的业务需求。
在这里插入图片描述


http://www.ppmy.cn/devtools/102619.html

相关文章

Codeforces Round 953 (Div. 2) (A~D)

文章目录 写在前面A. Alice and Books思路code B. New Bakery思路code C. Manhattan Permutations思路code D. Elections思路code Codeforces Round 953 (Div. 2) 写在前面 今天挑了一场div2来打,感觉这场div2的难度比暑假div2的难度低很多,A~D这四道题…

获取文件属性/库Lib

获取文件属性 stat 函数 man 2 stat #include <sys/types.h> #include <sys/stat.h> #include <unistd.h>int stat(const char *path, struct stat *buf); 功能&#xff1a;获取文件属性 参数&#xff1a; path&#xff1a;文件路径名buf&#xff1a;保存文…

【Qt】多元素控件QTreeWidget

多元素控件QTreeWidget 使用QTreeWidget表示一个树型结构&#xff0c;里面的每一个元素都是QTreeWidgetItem&#xff0c;每个QTreeWidgetItem可以包含多个文本和图标&#xff0c;每个文本/图标表示一列。 可以给QTreeWidget设置顶层结构&#xff08;顶层节点可以有多个&#…

C#实现文件的上传

using System; using System.IO; using System.Net.Http; using System.Threading.Tasks;class Program {static async Task Main(string[] args){string apiUrl "http://example.com/upload"; // 替换为你的上传API地址string filePath "C:\path\to\your\fil…

在线BLOG网

TOC springboot0785在线BLOG网 第1章 绪论 1.1课题背景 计算机的普及和互联网时代的到来使信息的发布和传播更加方便快捷。人们可以通过计算机上的浏览器访问多个应用系统&#xff0c;从中获取一些可以满足用户生活需求的管理系统。网站系统有时更像是一个大型“展示平台”…

提升学术论文质量的智能助手:ChatGPT

提升学术论文质量的智能助手&#xff1a;ChatGPT 前言ChatGPT的核心功能ChatGPT的优势具体应用案例局限性与最佳实践结语 前言 在这个知识爆炸的时代&#xff0c;学术研究已成为推动社会进步和科技发展的重要力量。每一篇论文的撰写&#xff0c;都是对人类知识边界的一次探索和…

摄影曝光:曝光模式认知

写在前面 学习整理《摄影曝光&#xff1a;拍出好照片的49个关键技法》读书笔记博文内容涉及曝光模式简单认知适合小白认知理解不足小伙伴帮忙指正 &#x1f603;,生活加油 99%的焦虑都来自于虚度时间和没有好好做事&#xff0c;所以唯一的解决办法就是行动起来&#xff0c;认真…

数学建模学习(125):使用Python实现灰色关联分析从理论到实战

认真理解案例和对应代码,代码都可以当作模板使用 文章目录 1. 引言2. 灰色关联分析理论2.1 灰色关联分析的基本思想2.2 灰色关联分析的计算步骤3. 案例分析:行业对GDP的影响分析3.1 数据集3.2 Python代码实现4 案例分析:不同地区对环境污染的贡献分析4.1 数据集4.2 实现步骤…

约 数个数

对于一个数 其中&#xff1a;是的各个质因数&#xff0c;上式是的质因数乘积式。 约数个数&#xff1a; 约数之和&#xff1a; step1&#xff1a; 采用分解质因数的方法&#xff0c;计算出的每一个质因数的次数 &#xff08;分解质因数的blog&#xff1a;http://t.csdni…

【从问题中去学习k8s】k8s中的常见面试题(夯实理论基础)(十五)

本站以分享各种运维经验和运维所需要的技能为主 《python零基础入门》&#xff1a;python零基础入门学习 《python运维脚本》&#xff1a; python运维脚本实践 《shell》&#xff1a;shell学习 《terraform》持续更新中&#xff1a;terraform_Aws学习零基础入门到最佳实战 《k8…

【NO.11】LeetCode经典150题-274. H 指数

文章目录 【NO.11】LeetCode经典150题-274. H 指数解题&#xff1a;二分搜索 【NO.11】LeetCode经典150题-274. H 指数 274. H 指数 【中等】 给你一个整数数组 citations &#xff0c;其中 citations[i] 表示研究者的第 i 篇论文被引用的次数。计算并返回该研究者的 h 指数…

Java学习第三天

总体三部分内容&#xff1a;数据类型转换、运算符使用、调用Java提供的程序 数据类型转换&#xff1a; 1.自动类型转换 类型范围小的可以直接转换给类型范围大的变量&#xff1b;例如int类型可以直接赋值为long型 int a 10; long b a; char字符型在计算机底层是一个数字…

【虚拟化】KVM常用命令操作(virsh虚拟机常用操作之开关|连接|自启|克隆|快照)

目录 ​编辑一、KVM概述 1.1 KVM工具栈 1.2 libvirt架构概述 二、使用virsh管理虚拟机 三、kvm基本功能管理 1.帮助命令 2.KVM的配置文件存放目录 3.查看虚拟机状态 4.虚拟机关机与开机 5.强制虚拟机系统关闭电源 6.通过配置文件启动虚拟机系统 7.修改虚拟机配置文…

记一次事务里发普通消息的线上问题排查过程

1 结论 结论先行&#xff1a;事务MQ的使用场景&#xff0c;使用方式一定得正确&#xff0c;稍有不慎&#xff0c;可能就会带来数据不一致问题。 2 问题背景及现象 3 排查过程 3.1 初次分析 发现问题&#xff0c;及时修复&#xff0c;加完锁上线&#xff0c;以为问题修复了&a…

ps笔刷设置使用介绍

形状动态 建议开启&#xff0c;作用是笔刷会有粗细变换 传递 不透明度抖动 . 选择钢笔压力&#xff0c;作用就是压感&#xff0c;压力值&#xff0c;有粗细深浅轻重变化 调到这画的时候就不会特别浅 流量抖动 选择钢笔压力&#xff0c;开了就有虚边 方便画过渡。 一般画…

<Godot>工厂游戏练习笔记一<2D网格地图>

1、编写网格数据类&#xff0c;用于存储网格地图中的数据&#xff1a; class_name Grid2D_Data## 单元格数据,传入一个场景 var data:Resource:set(val):if val ! null:data val ## 网格长宽 var grid_size:Vector2i Vector2i(10,10):set(val):if val:grid_size val ## 网格…

经验笔记:理解和保障JWT的安全性

经验笔记&#xff1a;理解和保障JWT的安全性 引言 在软件开发领域&#xff0c;特别是Web应用开发中&#xff0c;JWT (JSON Web Tokens) 是一种广泛使用的认证机制。JWT不仅能够简化客户端与服务端之间的身份验证流程&#xff0c;还能增强数据传输的安全性。本文将深入探讨JWT…

Linux基础1-基本指令5(more,less,head,tail, | ,find)

本章继续整理其他linux基本指令 一.本章重点 1.more和less命令查看大文本 2.head和tail命令查看小文本和日志 3.使用管道多次处理信息 4.find指令 二.more和less more命令和less命令常用来查看大文本&#xff0c;其中less可以使用上下键快速浏览文本 使用方式 more文件 …

Flask 安装和应用

一、环境安装 1、 conda create -n flask python3.8 2、 conda activate flask3、 pip install Flask -i https://pypi.mirrors.ustc.edu.cn/simple 4、 python3 import importlib.metadata# 获取 Flask 版本信息 version importlib.metadata.version(flask) print(vers…

JavaScript RegExp 对象

RegExp 对象是 JavaScript 中用于处理正则表达式的核心功能。正则表达式&#xff08;Regular Expressions&#xff09;是一种用于匹配字符串中字符模式的工具&#xff0c;可以用于搜索、替换、验证、提取等操作。以下是对 RegExp 对象的详细介绍&#xff0c;包括它的构造函数、…