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

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

在这里插入图片描述

简单工厂模式(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:
    # 定义一个静态方法,用于创建产品实例
    @staticmethod
    def create_product(type):
        # 根据传入的类型参数决定创建哪种具体产品实例
        if type == 'A':
            return ConcreteProductA()
        elif type == 'B':
            return ConcreteProductB()
        # 如果传入的类型既不是'A'也不是'B',则返回None
        return 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):
        pass

class 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:
    @staticmethod
    def 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):
        pass

class MySQLConnection(DatabaseConnection):
    def connect(self):
        print("Connecting to MySQL database...")

class SQLiteConnection(DatabaseConnection):
    def connect(self):
        print("Connecting to SQLite database...")

class DatabaseConnectionFactory:
    @staticmethod
    def 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):
        pass

class WindowsButton(Button):
    def render(self):
        print("Rendering Windows style button.")

class LinuxButton(Button):
    def render(self):
        print("Rendering Linux style button.")

class ButtonFactory:
    @staticmethod
    def 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):
        pass

class 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:
    @staticmethod
    def 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):
        pass

class 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:
    @staticmethod
    def 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.mfbz.cn/a/553323.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++算法题 - 矩阵

目录 36. 有效的数独54. 螺旋矩阵48. 旋转图像73. 矩阵置零289. 生命游戏 36. 有效的数独 LeetCode_link 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。 数字 1-9 在每一列只能出现…

【IoTDB 线上小课 02】开源增益的大厂研发岗面经

还有友友不知道我们的【IoTDB 视频小课】系列吗&#xff1f; 关于 IoTDB&#xff0c;关于物联网&#xff0c;关于时序数据库&#xff0c;关于开源...给我们 5 分钟&#xff0c;持续学习&#xff0c;干货满满~ 5分钟学会 大厂研发岗面试 之前的第一期小课&#xff0c;我们听了 I…

SpringMVC(二)【请求与响应】

0、测试环境 我们简化开发&#xff0c;创建一个简单的环境&#xff08;因为没有其它包比如 service、dao&#xff0c;所以这里不用 Spring 容器&#xff0c;只用 SpringMVC 容器&#xff09;&#xff1a; Servelet 容器配置&#xff1a; package com.lyh.config;import org.s…

jmeter及PTS压测介绍和使用

一、常用压测工具&#xff1a; loadrunner apache ab&#xff08;单接口压测最方便&#xff09; jmeter 阿里云PTS&#xff08;原生上传jmeter脚本进行压测&#xff09; 二、jmeter可以压测不同的协议和应用 web http https jdbc for database TCP 三、使用场景及优点 1、功能…

飞行机器人专栏(十四)-- Kinect DK 人体骨骼点运动提取方法

系列文章目录 Ubuntu 18.04/20.04 CV环境配置&#xff08;下&#xff09;--手势识别TRTposeKinect DK人体骨骼识别_ubuntu kinect骨骼测试-CSDN博客文章浏览阅读1.3k次。trt_pose_ros kinect实现手势识别和人体骨骼识别&#xff0c;用于机器人运动控制参考_ubuntu kinect骨骼测…

SpringCloud(一)

微服务框架 一、分布式架构 分布式架构︰根据业务功能对系统进行拆分&#xff0c;每个业务模块作为独立项目开发&#xff0c;称为一个服务。 优点: 降低服务耦合有利于服务升级拓展 微服务是一种经过良好架构设计的分布式架构方案&#xff0c;微服务架构特征: 单一职责:微…

【函数式接口使用✈️✈️】通过具体的例子实现函数结合策略模式的使用

目录 前言 一、核心函数式接口 1. Consumer 2. Supplier 3. Function,> 二、场景模拟 1.面向对象设计 2. 策略接口实现&#xff08;以 Function 接口作为策略&#xff09; 三、对比 前言 在 Java 8 中引入了Stream API 新特性&#xff0c;这使得函数式编程风格进…

数据库工具解析之 OceanBase 数据库导出工具

背景 大多数的数据库都配备了自己研发的导入导出工具&#xff0c;对于不同的使用者来说&#xff0c;这些工具能够发挥不一样的作用。例如&#xff1a;DBA可以使用导数工具进行逻辑备份恢复&#xff0c;开发者可以使用导数工具完成系统间的数据交换。这篇文章主要是为OceanBase…

编曲知识20:人声和声处理 分轨导出 总线处理

和声处理 和声 声像注意不要和主旋律重叠 各个效果器的处理幅度可以更大 呼吸音可直接去掉 尽量不要和主旋律共用一个混响延迟轨 注意音量、注意主次 和声拓展-模拟合唱 录制两轨同八度的主旋律或低八度高八度的主旋律 声像左右分配 音量拉低 将各个合唱轨进行失真处理 …

【Pytorch】VSCode实用技巧 - 默认终端修改为conda activate pytorch

VScode修改配置使得启动终端为conda环境 VScode跑项目&#xff0c;在启动pytorch项目时往往会有千奇百怪的问题&#xff0c;最常见的就是显示“conda activate pytorch”后会要求“conda init”&#xff0c;但输入后实际上也不行&#xff0c;这是因为VSCode默认终端为 Powersh…

网站模板-慈善捐赠基金会网站模板 Bootstrap4 html

目录 一.前言 二.预览 三.下载链接 一.前言 这是一个慈善网站的页面。页面包含了导航栏、横幅部分、关于、使命、新闻、活动、捐赠和页脚等不同的部分。该网站还包含了一些CSS样式和JavaScript脚本来实现交互和样式效果。 这个网站的具体结构如下&#xff1a; 导航栏部分&a…

kafka---topic详解

一、分区与高可用 在Kafka中,事件(events 事件即消息)是以topic的形式进行组织的;同时topic是分区(partitioned)的,这意味着一个topic分布在Kafka broker上的多个“存储桶”(buckets)上。这种数据的分布式放置对于可伸缩性非常重要,因为它允许客户端应用程序同时从多个…

第十三章 使用深度和法线纹理

获取深度和法线纹理 背后的原理 深度纹理是一张渲染纹理,它里面存储的像素值不是颜色,而是一个高精度的深度值。深度值范围是[0, 1],非线性分布的。这些深度值来自于顶点变换后得到的归一化的设备坐标(NDC)。一个模型想要被绘制在屏幕上,需要把它的顶点从模型空间变换到齐…

OpenCV从入门到精通实战(三)——全景图像拼接

全景图像拼接实现 定义 Stitcher 的类&#xff0c;用于实现两张图片的拼接。使用的技术是基于 SIFT 特征点检测与匹配&#xff0c;以及利用视角变换矩阵来对齐和拼接图像。 import numpy as np import cv2class Stitcher:#拼接函数def stitch(self, images, ratio0.75, repro…

云手机助力舆情监测,智慧引领信息时代

随着信息时代的到来&#xff0c;舆情监测已成为政府、企业、高校、金融机构等各行业的必备利器。在这个信息爆炸的时代&#xff0c;如何及时准确地感知民意、把握市场动态&#xff0c;已成为各界迫切需要解决的问题。而云手机作为信息时代的新生力量&#xff0c;在舆情监测方面…

C++ UML 类图介绍与设计

1 类图概述 UML(Unified Modeling Language)&#xff0c;即统一建模语言&#xff0c;是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。UML从目标系统的不同角度出发&#xff0c;定义了用例图、类图、对象图、状态图、活动图…

PostgreSQL的学习心得和知识总结(一百三十八)|深入理解PostgreSQL数据库之Protocol message构造和解析逻辑

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

牛客 NC205 跳跃游戏(三)【中等 贪心 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/14abdfaf0ec4419cbc722decc709938b 思路 参考答案Java import java.util.*;public class Solution {/*** 代码中的类名、方法名、参数名已经指定&#xff0c;请勿修改&#xff0c;直接返回方法规定的值即可*** …

带缓存的输入输出流(I/O)

文章目录 前言一、带缓冲的输入输出流是什么&#xff1f;二、使用方法 1.BufferedInputStream与BufferedOutputStream类2.BufferedReader与BufferedWriter类总结 前言 输入输出流可以视为&#xff0c;从A点把货物搬运至B点。那么带缓冲的意思可以视为用货车把A点的货物搬运至B点…

代码随想录算法训练营DAY28(记录)|C++回溯算法Part.5|491.递增子序列、46.全排列、47.全排列II

文章目录 491.递增子序列思路伪代码CPP代码优化代码 46.全排列思路伪代码CPP代码 47.全排列IICPP代码 491.递增子序列 力扣题目链接 文章链接&#xff1a;491.递增子序列 视频连接&#xff1a;回溯算法精讲&#xff0c;树层去重与树枝去重 | LeetCode&#xff1a;491.递增子序列…
最新文章