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

news2024/11/28 0:48:41

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

在这里插入图片描述

简单工厂模式(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.coloradmin.cn/o/1603762.html

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

相关文章

超平实版Pytorch CNN Conv2d

torch.nn.Conv2d 基本参数 in_channels (int) 输入的通道数量。比如一个2D的图片&#xff0c;由R、G、B三个通道的2D数据叠加。 out_channels (int) 输出的通道数量。 kernel_size (int or tuple) kernel&#xff08;也就是卷积核&#xff0c;也可…

基于Springboot的社区防疫物资申报系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的社区防疫物资申报系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系…

Netty-NioServerSocketChannel与NioSocketChannel

NioServerSocketChannel NioServerSocketChannel是netty服务端的channel。在ServerbootStrap的bind方法中&#xff0c;通过反射&#xff0c;实例化对象NioServerSocketChannel。   NioServerSocketChannel对象实例化的过程中。 AbstractChannel中实例化channel的id&#xff…

TexStudio + MikTex 手动安装宏包

遇到上面这个 “宏包安装” 提示窗口后&#xff0c;设置来源为本地&#xff0c;随后在这个网址 https://mirrors.ustc.edu.cn/CTAN/systems/win32/miktex/tm/packages/ 下载所需的宏包&#xff0c;放到本地仓库里&#xff0c;即可 有三个宏包是必须要有的&#xff0c;它们是索…

UTS iOS插件

1、UTS插件无法出现 再uniapp x中使用时&#xff0c;必须给这个插件高度和宽度&#xff0c;否则出不来&#xff01; <uts-hello-view buttonText"点击按钮内容" style"width:375px;height: 375px;background-color: aqua;"></uts-hello-view>…

美业连锁门店收银系统源码-如何查看收款门店对应的加盟商?

美业管理系统源码 博弈美业SaaS系统 连锁多门店美业收银系统源码 多门店管理 / 会员管理 / 预约管理 / 排班管理 / 商品管理 / 促销活动 PC管理后台、手机APP、iPad APP、微信小程序 第一步&#xff1a; 登录pc管理后端 第二步&#xff1a; 进入企业组织管理-门店管理&a…

遥测终端赋能水库泄洪监测预警,筑牢度汛安全防线!

4月10日&#xff0c;水利部召开水库安全度汛视频会议。会议要求着力强化水库防洪“四预”措施&#xff0c;加快构建雨水情监测预报“三道防线”&#xff0c;完善预警信息发布机制&#xff0c;推进数字孪生水利工程建设&#xff0c;为科学调度指挥决策提供支持。强调坚决牢牢守住…

HTML5漫画风格个人介绍源码

源码介绍 HTML5漫画风格个人介绍源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面&#xff0c;重定向这个界面 效果截图 源码下载 HTML5漫画风格…

如何在ubuntu上使用clash

下载CLASH软件 修改配置文件 解压之后&#xff0c;将.env文件中的URL改为自己订阅的URL&#xff0c;然后再执行start.sh脚本 最后按照提示&#xff0c;将clash.sh添加到环境变量 如何修改端口 在start.sh中更改 祝大家在ubuntu上玩得开心

Linux设置真实IP

1.查看ens33网卡信息 vi /etc/sysconfig/network-scripts/ifcfg-ens33 #添加以下内容 BOOTPROTODHCP #协议类型 dhcp bootp none ONBOOTyes #启动时是否激活 yes | no#修改文件完成后&#xff0c;重启网络 service network restartping www.baidu.com #验证网络是否生效 ifco…

基于SpringBoot框架的智慧食堂

采用技术 基于SpringBoot框架实现的web的智慧社区系统的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBootMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 页面展示效果 系统功能 系统首页 用户注册页面 菜品信息页面 …

Postman之全局变量与环境变量配置

实际开发中可能需要不停切换环境&#xff0c;接口中来回输入环境地址比较麻烦&#xff0c;故而通过定义变量来节约频繁更换测试地址所耗费的时间。Postman 允许定义自己的全局变量&#xff08;Globals&#xff09;与环境变量&#xff08;Environment&#xff09;&#xff0c;最…

Ribbon 添加右侧区域菜单项

效果图如下所示&#xff1a; 类似与上图效果所示&#xff0c;代码如下&#xff1a; RibbonPage* pageHome1 ribbonBar()->addPage(tr("Home")); //实现代码&#xff1a; { QMenu* menuOptions ribbonBar()->addMenu(tr("Options"))…

java mockito工具

java mockito工具 Mockito 中文文档 本文档参考hehonghui/mockito-doc-zh项目&#xff0c;如有侵权&#xff0c;请联系删除 Mockito框架官方地址mockito&#xff0c;文档地址。 Mockito库能够Mock对象、验证结果以及打桩(stubbing)。 该文档您也可以通过http://mockito.org获…

EFK环境搭建(基于K8S环境部署)

目录 一.环境信息二.安装nfs供应商三.安装elasticsearch四.安装kibana组件五.安装fluentd 一.环境信息 1.服务器及k8s版本 IP地址主机名称角色版本192.168.40.180master1master节点1.27192.168.40.181node1node1节点1.27192.168.40.182node2node2节点1.27 2.部署组件版本 序…

爬虫入门——Request请求

目录 前言 一、Requests是什么&#xff1f; 二、使用步骤 1.引入库 2.请求 3.响应 三.总结 前言 上一篇爬虫我们已经提及到了urllib库的使用&#xff0c;为了方便大家的使用过程&#xff0c;这里为大家介绍新的库来实现请求获取响应的库。 一、Requests是什么&#xff1…

Py之fireworks-ai:fireworks-ai的简介、安装和使用方法、案例应用之详细攻略

Py之fireworks-ai&#xff1a;fireworks-ai的简介、安装和使用方法、案例应用之详细攻略 目录 fireworks-ai的简介 fireworks-ai的安装和使用方法 1、安装 2、使用方法 # 使用Fireworks客户端库与某个预训练模型进行交互 fireworks-ai的案例应用 LLMs之Agent之Self-ask …

mac IDEA激活 亲测有效

1、官网下载mac版本IDEA并安装 2、打开激活页面 3、下载脚本文件 链接: https://pan.baidu.com/s/1I2BqdfxSJv1A96422rflnA?pwdm494 提取码: m494 4、命令行到该界面&#xff0c;执行 sudo bash idea.sh 可能出现的问题&#xff1a; 查看sh文件&#xff0c;targetFilePath…

【Day 1】HTML 与 CSS

1 前端 网站的工作流程&#xff1a; 首先我们需要通过浏览器访问发布到前端服务器中的前端程序&#xff0c;这时候前端程序会将前端代码返回给浏览器浏览器得到前端代码&#xff0c;此时浏览器会将前端代码进行解析&#xff0c;然后展示到浏览器的窗口中&#xff0c;这时候我…

Python爬取猫眼电影票房 + 数据可视化

目录 主角查看与分析 爬取可视化分析猫眼电影上座率前10分析猫眼电影票房场均人次前10分析猫眼电影票票房占比分析 主角查看与分析 爬取 对猫眼电影票房进行爬取&#xff0c;首先我们打开猫眼 接着我们想要进行数据抓包&#xff0c;就要看网站的具体内容&#xff0c;通过按F12…