设计模式学习(六)——《大话设计模式》

设计模式学习(六)——《大话设计模式》

在这里插入图片描述

简单工厂模式(Simple Factory Pattern),也称为静态工厂方法模式,它属于类创建型模式。

在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

工作原理

简单工厂模式的核心思想是有一个中心化的类(简单工厂类),这个类的职责非常明确:负责创建其他类的实例。

客户端只需要传递给工厂类一个参数,就可以获取到必须的实例对象,而无需关心其创建细节。

结构组成

简单工厂模式主要包含以下三个角色:

工厂角色(Factory):这是实现创建所有实例的内部逻辑的类。通常由一个具体类实现。
抽象产品角色(Product):这是一个抽象类或接口,新创建的对象通常都实现或继承自这个类或接口。
具体产品角色(Concrete Product):这是工厂类创建的目标类,继承自抽象产品角色或实现了产品角色定义的接口。

优缺点

优点:

工厂类含有必要的逻辑判断,可以决定在什么时候创建哪一个产品类的实例。使用者可以免除直接创建产品对象的责任,而仅仅"消费"产品。
客户端无需知道所创建具体产品的类名,只需知道参数即可。

缺点:

  • 工厂类集中了所有产品的创建逻辑,一旦这个工厂不能工作,整个系统都会受到影响。
  • 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品种类较多时,会使得系统非常复杂。
  • 简单工厂模式由于使用了静态方法,造成工厂角色无法形成基于继承的等级结构。

应用场景

简单工厂模式适用于以下场景:

工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端不需要知道具体产品类的类名,只需要知道参数即可。

示例代码

以Python为例,展示一个简单工厂模式的实现:

# 定义一个抽象产品类
class Product:# 定义一个使用产品的抽象方法,具体实现留给子类def use(self):pass# 定义具体产品类A,继承自Product
class ConcreteProductA(Product):# 实现父类的use()方法def use(self):print("Inside ConcreteProductA's use() method.")# 定义具体产品类B,继承自Product
class ConcreteProductB(Product):# 实现父类的use()方法def use(self):print("Inside ConcreteProductB's use() method.")# 定义简单工厂类
class SimpleFactory:# 定义一个静态方法,用于创建产品实例@staticmethoddef create_product(type):# 根据传入的类型参数决定创建哪种具体产品实例if type == 'A':return ConcreteProductA()elif type == 'B':return ConcreteProductB()# 如果传入的类型既不是'A'也不是'B',则返回Nonereturn None# 客户端代码
# 使用简单工厂类创建一个类型为'A'的产品实例
product = SimpleFactory.create_product('A')
# 调用产品实例的use()方法
product.use()

首先定义了一个Product抽象类,然后定义了两个具体的产品类ConcreteProductA和ConcreteProductB,它们都继承自Product类并实现了use()方法。SimpleFactory类通过其静态方法create_product根据传入的类型参数来决定创建哪种具体产品实例。客户端代码仅需通过简单工厂类即可获取到所需的产品实例,无需直接跟具体的产品类发生耦合,从而简化了客户端的使用过程。

在这个例子中,SimpleFactory::create_product方法根据传入的字符串参数决定创建哪种类型的产品实例。这个方法返回一个实现了Product特征的对象的Box(一个智能指针),这样我们就可以在运行时多态地调用operation方法。

定义一个产品特征(trait),以及两种具体的产品结构体

// 定义产品特征
trait Product {fn operation(&self) -> String;
}// 第一个具体产品
struct ConcreteProductA;impl Product for ConcreteProductA {fn operation(&self) -> String {String::from("结果来自于产品A")}
}// 第二个具体产品
struct ConcreteProductB;impl Product for ConcreteProductB {fn operation(&self) -> String {String::from("结果来自于产品B")}
}

定义一个简单工厂结构体,它有一个静态方法用于根据条件创建不同的产品实例:

// 简单工厂
struct SimpleFactory;impl SimpleFactory {// 静态方法,根据类型创建不同的产品实例fn create_product(product_type: &str) -> Box<dyn Product> {match product_type {"A" => Box::new(ConcreteProductA),"B" => Box::new(ConcreteProductB),_ => panic!("不支持的产品类型"),}}
}

使用简单工厂来创建和使用产品:

fn main() {let product_a = SimpleFactory::create_product("A");println!("{}", product_a.operation());let product_b = SimpleFactory::create_product("B");println!("{}", product_b.operation());
}

UML类图

工厂(Factory) - 负责创建产品对象的类。它通常包含一个或多个方法,这些方法用于根据输入参数决定创建哪种具体产品的实例。
抽象产品(Abstract Product) - 由一个接口或抽象类表示,定义了产品对象的公共接口。
具体产品(Concrete Product) - 实现或继承自抽象产品,表示具体的产品对象。

        +-------------------+|    <<interface>>  ||    Abstract       ||    Product        |+-------------------+^  ^|  |
+---------------+  +----------------+
|                                  |
|                                  |
|                                  |
+-------------------+   +-------------------+
|    Concrete       |   |    Concrete       |
|    Product A      |   |    Product B      |
+-------------------+   +-------------------+^                        ^|                        ||                        |+-----------+------------+||+-------------------+|     Factory       |+-------------------+| +createProduct()  |+-------------------+
  • Abstract Product 表示产品的公共接口,它定义了所有具体产品应该实现的操作。
  • Concrete Product A 和 Concrete Product B 是实现了抽象产品接口的具体类,代表了不同类型的产品。
  • Factory 是一个包含 createProduct 方法的类。这个方法根据输入参数决定并返回具体产品的实例。在 Rust 的实现中,这个角色通常通过一个结构体(如 SimpleFactory)和一个关联函数(如 create_product)来实现。

具体应用和使用场景

日志记录:

在需要实现日志记录功能时,可以使用简单工厂模式来创建不同类型的日志记录器(如文件日志记录器、数据库日志记录器等)。这样,应用程序可以根据配置或运行时条件选择合适的日志记录方式,而无需修改现有代码。

#有一个应用,需要根据不同的环境(开发环境、生产环境)来选择不同的日志记录方式(控制台日志、文件日志)。
class Logger:def log(self, message):passclass ConsoleLogger(Logger):def log(self, message):print(f"Console log: {message}")class FileLogger(Logger):def log(self, message):with open("app.log", "a") as file:file.write(f"File log: {message}\n")class LoggerFactory:@staticmethoddef get_logger(environment):if environment == 'development':return ConsoleLogger()elif environment == 'production':return FileLogger()else:raise ValueError("Invalid environment")# 客户端代码
logger = LoggerFactory.get_logger('development')
logger.log("This is a log message.")

数据库访问:

在访问不同类型的数据库时(如MySQL、SQLite、Oracle等),可以通过简单工厂模式提供一个统一的接口来创建不同类型的数据库连接对象。这样,当需要更换数据库或同时支持多种数据库时,只需修改工厂类中的逻辑即可。

#需要连接不同类型的数据库时,可以定义一个简单工厂来创建不同类型的数据库连接。
class DatabaseConnection:def connect(self):passclass MySQLConnection(DatabaseConnection):def connect(self):print("Connecting to MySQL database...")class SQLiteConnection(DatabaseConnection):def connect(self):print("Connecting to SQLite database...")class DatabaseConnectionFactory:@staticmethoddef get_database_connection(database_type):if database_type == 'MySQL':return MySQLConnection()elif database_type == 'SQLite':return SQLiteConnection()else:raise ValueError("Invalid database type")# 客户端代码
db_connection = DatabaseConnectionFactory.get_database_connection('SQLite')
db_connection.connect()

GUI组件创建:

在开发图形用户界面(GUI)应用程序时,简单工厂模式可以用来创建不同类型的GUI组件,如按钮、文本框、复选框等。根据不同的需求或风格,可以轻松切换组件的具体实现。

#GUI应用程序中,根据不同的需求创建不同类型的按钮。
class Button:def render(self):passclass WindowsButton(Button):def render(self):print("Rendering Windows style button.")class LinuxButton(Button):def render(self):print("Rendering Linux style button.")class ButtonFactory:@staticmethoddef get_button(os_type):if os_type == 'Windows':return WindowsButton()elif os_type == 'Linux':return LinuxButton()else:raise ValueError("Invalid OS type")# 客户端代码
button = ButtonFactory.get_button('Linux')
button.render()

API客户端:

当应用程序需要与多个外部服务或API交互时,可以使用简单工厂模式来创建针对每个服务的API客户端实例。这种方式便于管理和维护与各个服务的交互逻辑。

#有多个外部服务,根据服务类型创建对应的API客户端实例。
class APIClient:def fetch_data(self):passclass ServiceA_APIClient(APIClient):def fetch_data(self):print("Fetching data from Service A")class ServiceB_APIClient(APIClient):def fetch_data(self):print("Fetching data from Service B")class APIClientFactory:@staticmethoddef get_api_client(service_type):if service_type == 'ServiceA':return ServiceA_APIClient()elif service_type == 'ServiceB':return ServiceB_APIClient()else:raise ValueError("Invalid service type")# 客户端代码
api_client = APIClientFactory.get_api_client('ServiceA')
api_client.fetch_data()

支付方式处理:

在电子商务系统中,根据用户选择的支付方式(如信用卡支付、支付宝、微信支付等),使用简单工厂模式动态创建对应的支付处理对象。这样可以轻松扩展新的支付方式,同时保持代码的清晰和可维护性。

#电子商务系统中,根据用户选择的支付方式处理支付。
class PaymentProcessor:def process_payment(self, amount):passclass CreditCardProcessor(PaymentProcessor):def process_payment(self, amount):print(f"Processing ${amount} payment through Credit Card.")class PayPalProcessor(PaymentProcessor):def process_payment(self, amount):print(f"Processing ${amount} payment through PayPal.")class PaymentProcessorFactory:@staticmethoddef get_payment_processor(method):if method == 'CreditCard':return CreditCardProcessor()elif method == 'PayPal':return PayPalProcessor()else:raise ValueError("Invalid payment method")# 客户端代码
payment_processor = PaymentProcessorFactory.get_payment_processor('PayPal')
payment_processor.process_payment(100)

使用场景总结:

  1. 当需要根据输入或条件创建多个类的实例时,而这些类又有共同的父类或接口。
  2. 当创建对象的逻辑比较复杂,但又希望对客户端隐藏这些复杂性时。
  3. 当系统需要灵活地添加新产品时,而不希望对现有代码造成太大影响。

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

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

相关文章

构建现代网页的引擎:WebKit架构揭秘

在网络信息迅猛增长的今天&#xff0c;浏览器已经成为我们接触世界的重要窗口。而在浏览器的核心&#xff0c;有一个强大的引擎在默默地支撑着网页的渲染和执行&#xff0c;这就是WebKit。 WebKit的核心组件 WebKit作为开源浏览器引擎&#xff0c;由苹果公司发展而来&#x…

排序(四)——归并排序 + 外排序

目录 1.归并排序递归实现 代码 2.归并排序非递归 代码 3.比较快排、归并和堆排序 4.归并排序实现外排序 1.归并排序递归实现 我们之前对两个有序数组进行排序就用到了归并的思想&#xff0c;对于两个有序数组&#xff0c;我们分别取他们首元素比较大小&#xff0c;取小的插…

Unity给地图物体添加对撞机

在项目/Assets下创建Prefabs文件夹 选择素材拖入层级下&#xff0c;注意此时地图素材有可能看不到&#xff0c;此时选择Tilemap在检查器中修改图层顺序调至最低。 添加对撞机 选择素材&#xff0c;在检查器中点击添加组件Box Collider 2D&#xff0c;将素材拖入Prefabs文件下…

【Arduino IDE 环境配置】

目录 Arduino IDE 环境配置 1. 安装方式2. 操作方法&#xff08;Arduino中文社区&#xff09; 2.1. 安装Arduino IDE2.2. 下载固件2.3. 修改Arduino IDE语言2.4. 添加开发板管理网址2.5. 运行离线包2.6. 检查安装是否成功 下载Arduino IDE&#xff1a; 如果你还没有安装Arduin…

如何使用Postgres的JSONB数据类型进行高效查询

文章目录 解决方案1. 创建包含JSONB列的表2. 插入JSON数据3. 使用GIN索引加速查询4. 执行高效的JSONB查询 示例代码解释 PostgreSQL的JSONB数据类型提供了一种灵活的方式来存储和查询JSON格式的数据。JSONB不仅允许你在PostgreSQL数据库中存储JSON文档&#xff0c;而且还对这些…

CentOS常见的命令用法和示例

1. 文件和目录管理 1.1 ls 描述&#xff1a; 列出目录内容。 用法&#xff1a; ls [选项] [目录] 示例&#xff1a; ls -l /home 1.2 cd 描述&#xff1a; 切换当前工作目录。 用法&#xff1a; cd [目录路径] 示例&#xff1a; cd /var/www 1.3 pwd 描述&am…

(delphi11最新学习资料) Object Pascal 学习笔记---第10章第1节(定义属性)

第10章 属性和事件 ​ 在过去的三章中&#xff0c;我已经介绍了Object Pascal中面向对象编程&#xff08;OOP&#xff09;的基础知识&#xff0c;解释了这些概念并展示了大多数面向对象编程语言中通用特性是如何具体实现的。自Delphi的早期&#xff0c;Object Pascal语言就是一…

科技云报道:大模型加持后,数字人“更像人”了吗?

科技云报道原创。 北京冬奥运AI 虚拟人手语主播、杭州亚运会数字人点火、新华社数字记者、数字航天员小诤…当随着越来越多数字人出现在人们生活中&#xff0c;整个数字人行业也朝着多元化且广泛的应用方向发展&#xff0c;快速拓展到不同行业、不同场景。 面向C端&#xff0…

C++实现四阶Runge-Kutta

#include <iostream>// 定义微分方程 dy/dx f(x, y) double f(double x, double y) {return 2 * x y; }// 四阶Runge-Kutta方法求解微分方程 double rungeKutta(double x0, double y0, double h, double xn) {double x x0;double y y0;while (x < xn) {double k1 …

.NET开源免费的跨平台框架 - MAUI(附学习资料)

前言 前几天分享了一个.NET MAUI开源免费的UI工具包 - Uranium&#xff0c;然后技术群有不少同学问.NET MAUI是不是免费的&#xff1f;能做什么&#xff1f;今天特意写这篇文章来介绍一下.NET开源、免费&#xff08;基于MIT License&#xff09;的跨平台框架&#xff1a;MAUI。…

PostCSS概述

PostCSS概述 在前端开发中&#xff0c;CSS预处理器和后处理器都是非常重要的工具。它们可以帮助我们写出更干净、可维护的CSS代码&#xff0c;同时还提供了许多强大的功能&#xff0c;如变量、混入(mixin)、嵌套等。其中&#xff0c;PostCSS就是一款强大的CSS后处理器。 一、…

Java并发体系--LinkedBlockingDeque

LinkedBlockingDeque LinkedBlockingDeque是Java中的一个双向链表阻塞队列&#xff0c;实现了BlockingDeque接口。它是一个线程安全的队列数据结构&#xff0c;可以同时支持在队列的头部和尾部进行元素的添加和删除操作&#xff0c;并且在队列为空或已满时提供阻塞操作。 Lin…

【刷题笔记】第八天

文章目录 [928. 尽量减少恶意软件的传播 II](https://leetcode.cn/problems/minimize-malware-spread-ii/)方法1&#xff1a;dfs方法2&#xff1a;并查集 [GCD and LCM](https://vjudge.net.cn/problem/Aizu-0005)[Missing Bigram](https://vjudge.net.cn/problem/CodeForces-1…

基于springboot+vue+Mysql的简历系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

数据赋能(60)——要求:数据服务部门能力

“要求&#xff1a;数据服务部门实施数据赋能影响因素”是作为标准的参考内容编写的。 在实施数据赋能中&#xff0c;数据服务部门的能力体现在多个方面&#xff0c;关键能力如下图所示。 在实施数据赋能的过程中&#xff0c;数据服务部门应具备的关键能力如下。 业务理解和沟…

案例与脚本实践:DolphinDB 轻量级实时数仓的构建与应用

DolphinDB 高性能分布式时序数据库&#xff0c;具有分布式计算、事务支持、多模存储、以及流批一体等能力&#xff0c;非常适合作为一款理想的轻量级大数据平台&#xff0c;轻松搭建一站式的高性能实时数据仓库。 本教程将以案例与脚本的方式&#xff0c;介绍如何通过 Dolphin…

MySQL 的事务

事务概念 MySQL事务是一个或者多个的数据库操作&#xff0c;要么全部执行成功&#xff0c;要么全部失败回滚。 事务是通过事务日志来实现的&#xff0c;事务日志包括&#xff1a;redo log和undo log。 事务状态 事务有以下五种状态&#xff1a; 活动的部分提交的失败的中止的…

在win10中自定义文件夹右键菜单

在Windows 10中&#xff0c;右键点击文件夹空白区域可以快速访问一系列常用功能&#xff0c;如新建文件夹、粘贴、属性等。你可以根据自己的需求定制这个右键菜单&#xff0c;添加更多个性化的功能。本示例将向你展示如何在Windows 10中自定义文件夹右键菜单&#xff0c;让它更…

使用GAN做图像超分——SRGAN,ESRGAN

在GAN出现之前&#xff0c;使用的更多是MSE&#xff0c;PSNR,SSIM来衡量图像相似度&#xff0c;同时也使用他们作为损失函数。 但是这些引以为傲的指标&#xff0c;有时候也不是那么靠谱&#xff1a; MSE对于大的误差更敏感&#xff0c;所以结果就是会倾向于收敛到期望附近&am…

【深度学习】wandb模型训练可视化工具使用方法

【深度学习】wandb模型训练可视化工具使用方法 wandb简介功能介绍登陆注册以及API keysproject和runsproject和runs的关系 wandb的配置实验跟踪版本管理Case可视化分析可视化自动调参&#xff08;wandb.sweep&#xff09;配置wandb.sweep1.配置 sweep_config2.初始化 sweep con…