简单工厂模式

简单工厂模式详解

定义

简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,用于创建对象的实例。通过一个工厂类来决定实例化哪一个具体类,降低客户端与具体类之间的耦合。

对于长switch或者长if、else,且多处调用情形,可以考虑使用简单工厂模式。

特点

  • 封装实例化逻辑:将对象的创建集中在一个工厂类中。
  • 扩展性较弱:如果需要增加新产品,需要修改工厂类代码,违反开闭原则。

适用场景

  1. 客户端需要创建不同种类的对象,但不需要关心具体的实现。
  2. 需要对实例化的过程进行控制或封装。

使用案例

  1. 日志处理:根据日志类型(如文件日志、数据库日志)创建不同的日志处理器。
  2. 图形对象创建:根据用户选择创建不同的图形对象(如圆形、矩形)。
  3. 支付系统:根据支付方式(如支付宝、微信、银行卡)创建不同的支付对象。

实现代码

C++ 实现

#include <iostream>
#include <string>
#include <memory>// 产品基类
class Product {
public:virtual void use() = 0;virtual ~Product() {}
};// 具体产品 A
class ProductA : public Product {
public:void use() override {std::cout << "Using Product A" << std::endl;}
};// 具体产品 B
class ProductB : public Product {
public:void use() override {std::cout << "Using Product B" << std::endl;}
};// 工厂类
class SimpleFactory {
public:static std::unique_ptr<Product> createProduct(const std::string& type) {if (type == "A") {return std::make_unique<ProductA>();} else if (type == "B") {return std::make_unique<ProductB>();} else {return nullptr;}}
};// 客户端代码
int main() {auto product = SimpleFactory::createProduct("A");if (product) {product->use();}return 0;
}

C# 实现

using System;// 产品基类
public abstract class Product {public abstract void Use();
}// 具体产品 A
public class ProductA : Product {public override void Use() {Console.WriteLine("Using Product A");}
}// 具体产品 B
public class ProductB : Product {public override void Use() {Console.WriteLine("Using Product B");}
}// 工厂类
public class SimpleFactory {public static Product CreateProduct(string type) {return type switch {"A" => new ProductA(),"B" => new ProductB(),_ => null};}
}// 客户端代码
class Program {static void Main(string[] args) {Product product = SimpleFactory.CreateProduct("A");product?.Use();}
}

类图

«Abstract»
Product
+use()
ProductA
+use()
ProductB
+use()
SimpleFactory
+createProduct(type : string)

更多内容

扩展设计模式背景

简单工厂模式是较早被提出的创建型设计模式,虽然不属于 GoF 设计模式,但经常被当作一种基础设计手法,并作为引入工厂方法模式的过渡。以下是一些补充内容:


优点

  1. 职责集中:工厂类集中处理实例化逻辑,简化了客户端代码。
  2. 易于维护:修改实例化逻辑时,只需更改工厂类。
  3. 隐藏实现细节:客户端只需关心工厂接口,无需关心具体产品的实现。

缺点

  1. 扩展性差
    • 每增加一种新产品,都需要修改工厂类的代码。
    • 违反开闭原则(Open/Closed Principle)。
  2. 单一职责问题
    • 工厂类负责太多类型的产品创建,可能变得臃肿。
  3. 不适合复杂场景
    • 当产品之间有复杂的继承或依赖关系时,简单工厂模式的实现变得困难。

如何增强简单工厂模式

  1. 结合单例模式:将工厂类设计为单例,避免频繁创建工厂实例。

    public class SimpleFactory {private static readonly SimpleFactory instance = new SimpleFactory();private SimpleFactory() {}public static SimpleFactory Instance => instance;public Product CreateProduct(string type) {return type switch {"A" => new ProductA(),"B" => new ProductB(),_ => null};}
    }
    
  2. 结合配置文件或枚举:将产品类型和具体类之间的映射关系配置到文件或用枚举维护,提高灵活性。

    • 示例:通过映射关系动态加载产品:
      Dictionary<string, Func<Product>> productMap = new() {{ "A", () => new ProductA() },{ "B", () => new ProductB() }
      };public Product CreateProduct(string type) {return productMap.TryGetValue(type, out var factory) ? factory() : null;
      }
      
  3. 动态加载类(反射):在需要动态扩展产品时,工厂类可以使用反射加载产品类型:

    public Product CreateProduct(string type) {Type productType = Type.GetType(type);return productType != null ? (Product)Activator.CreateInstance(productType) : null;
    }
    

简单工厂模式与其他模式的比较

特性简单工厂模式工厂方法模式抽象工厂模式
复杂度
扩展性差(需修改工厂类)良好(新增工厂子类即可)非常灵活(支持多个产品族)
适用场景产品种类少,扩展性要求低的场景产品种类多但产品结构简单的场景产品种类多且结构复杂的场景

变体:Parameterized Factory

将产品的创建参数化,可以更灵活地配置对象:

  • 示例
    static std::unique_ptr<Product> createProduct(const std::string& type, int config) {if (type == "A") {return std::make_unique<ProductA>(config);} else if (type == "B") {return std::make_unique<ProductB>(config);}return nullptr;
    }
    

实践中的注意事项

  1. 产品不宜过多:如果产品种类繁杂,推荐升级到工厂方法模式或抽象工厂模式。
  2. 避免逻辑臃肿:工厂类的逻辑要简洁,复杂的创建逻辑可以委托给专门的创建类处理。
  3. 性能考虑:动态加载或反射可能影响性能,在高性能场景中需谨慎使用。

示例拓展

将简单工厂与单例模式结合,用于日志系统:

C++ 日志系统
#include <iostream>
#include <string>
#include <memory>class Logger {
public:virtual void log(const std::string& message) = 0;virtual ~Logger() {}
};class FileLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "File log: " << message << std::endl;}
};class ConsoleLogger : public Logger {
public:void log(const std::string& message) override {std::cout << "Console log: " << message << std::endl;}
};class LoggerFactory {
public:static std::unique_ptr<Logger> getLogger(const std::string& type) {if (type == "file") {return std::make_unique<FileLogger>();} else if (type == "console") {return std::make_unique<ConsoleLogger>();}return nullptr;}
};int main() {auto logger = LoggerFactory::getLogger("console");if (logger) {logger->log("Hello, world!");}return 0;
}

总结

简单工厂模式是一种结构简单但实用的设计模式,适合用于需求变化不频繁的小型项目或模块中,更多内容完善了简单工厂模式的局限性及改进方案,并扩展了实际应用案例,展示了模式的灵活性和变体的实现方法。但在扩展性要求高的场景中,推荐使用工厂方法模式或抽象工厂模式以增强灵活性。

ps:

本文为连载文章,更多内容关注后可在设计模式专栏内查看。

觉得文章不错,记得点赞、收藏,有任何问题欢迎评论探讨。

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

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

相关文章

嵌入式硬件电子电路设计(五)LDO低压差线性稳压器全面详解

引言&#xff1a; LDO&#xff08;Low Dropout Regulator&#xff0c;低压差线性稳压器&#xff09;是一种常用的电源管理组件&#xff0c;用于提供稳定的输出电压&#xff0c;同时允许较小的输入电压与输出电压之间的差值。LDO广泛应用于各种电子设备中&#xff0c;特别是在对…

D3基础:绘制圆形、椭圆形、多边形、线、路径、矩形

在D3.js中&#xff0c;可以通过SVG元素来创建各种几何图形。以下是D3.js中常用的几何图形及其简单的创建方法&#xff1a; 1. 圆形 (Circle) 圆形是最基本的形状之一&#xff0c;可以通过<circle>标签来创建。 <!DOCTYPE html> <html> <head><met…

17.100ASK_T113-PRO 配置QT运行环境(三)

前言 1.打开QT,新建项目. 做成以下效果,会QT都没有问题吧 编译输出: /home/book/LED_and_TempHumi/build-LED_and_TempHumi-100ask-Debug LED_and_TempHumi 2.下载程序与测试 设置运行环境 export QT_QPA_PLATFORMlinuxfb 这个地方还需要加字体,不然不会显示字体.

React 实现网页首页设计

目录 页面分解 项目初始化 项目结构 运行项目 页面分解 页面主要元素&#xff1a; Header&#xff08;导航栏&#xff09; 包含网站 logo 和导航菜单。Hero Section&#xff08;主横幅&#xff09; 大背景图片、标题文字、描述文字。Features Section&#xff08;功能展示…

[Go实战]:SSE消息推送

前言 在现代Web开发中&#xff0c;前后端分离已成为主流趋势。为了实现实时数据推送&#xff0c;Server-Sent Events (SSE) 是一种高效且易于实现的技术。本文将介绍如何在Go语言中实现SSE服务端&#xff0c;并在前端使用JavaScript进行集成&#xff0c;实现一个完整的实时数据…

使用OkHttp进行HTTPS请求的Kotlin实现

OkHttp简介 OkHttp是一个高效的HTTP客户端&#xff0c;它支持同步和异步请求&#xff0c;自动处理重试和失败&#xff0c;支持HTTPS&#xff0c;并且可以轻松地与Kotlin协程集成。OkHttp的设计目标是提供最简洁的API&#xff0c;同时保持高性能和低延迟。 为什么选择OkHttp …

【技术解析】Dolphinscheduler实现MapReduce任务的高效管理

MapReduce是一种编程模型&#xff0c;用于处理和生成大数据集&#xff0c;主要用于大规模数据集&#xff08;TB级数据规模&#xff09;的并行运算。本文详细介绍了Dolphinscheduler在MapReduce任务中的应用&#xff0c;包括GenericOptionsParser与args的区别、hadoop jar命令参…

Linux :进程间通信之管道

一、进程间通信 1.1 是什么和为什么 1、进程间通信是什么&#xff1f;&#xff1f; ——>两个或多个进程实现数据层面的交互&#xff0c;但是由于进程独立性的存在&#xff0c;导致通信的成本比较高。 2、既然通信成本高&#xff0c;那为什么还要通信呢&#xff1f;&…

Vue基础(2)_el和data的两种写法

举例&#xff1a; <div id"root"><h1>你好&#xff0c;{{name}}</h1> </div> el和data的2种写法 1.el有2种写法 (1).new Vue时候配置el属性。 // 第一种写法&#xff1a;new Vue时候配置el属性。// 优点&#xff1a;简单、直接new Vue({e…

【汇编语言】数据处理的两个基本问题(二) —— 解密汇编语言:数据长度与寻址方式的综合应用

文章目录 前言1. 指令要处理的数据有多长&#xff1f;1.1 通过寄存器指明数据的尺寸1.1.1 字操作1.1.2 字节操作 1.2 用操作符X ptr指明内存单元的长度1.2.1 访问字单元1.2.2 访问字节单元1.2.3 为什么要用操作符X ptr指明 1.3 其他方法 2. 寻址方式的综合应用2.1 问题背景&…

c++多态(深度刨析)

C系列-----多态 文章目录 C系列-----多态前言一、多态的概念二、多态的定义及实现2.1、多态构成的条件2.1.1、虚函数2.1.2、虚函数的重写 2.2、C11 override 和 final2.3、重载、覆盖(重写)、隐藏(重定义)的对比2.4、抽象类2.5、 接口继承和实现继承 三、多态的原理3.1、虚函数…

FPGA开发技能(9)快速生成约束XDC文件

文章目录 1.从Cadence导出csv约束文件2.python程序将csv导出为xdc文件。3.python生成exe4.exe使用注意事项5.传送门 前言&#xff1a; 作为一名FPGA工程师&#xff0c;通常公司会对该岗位的人有一定的硬件能力的要求&#xff0c;最基础的就是需要依据原理图的设计进行FPGA工程内…

css uniapp背景图宽度固定高度自适应可以重复

page {height: 100%;background-image: url(https://onlinekc.a.hlidc.cn/uploads/20241115/350f94aaf493d05625a7ddbc86c7804e.png);background-repeat: repeat;background-size: contain;} 如果不要重复 把background-repeat: repeat;替换background-repeat: no-repeat;

Stable Diffusion核心网络结构——U-Net

​ &#x1f33a;系列文章推荐&#x1f33a; 扩散模型系列文章正在持续的更新&#xff0c;更新节奏如下&#xff0c;先更新SD模型讲解&#xff0c;再更新相关的微调方法文章&#xff0c;敬请期待&#xff01;&#xff01;&#xff01;&#xff08;本文及其之前的文章均已更新&a…

学习threejs,使用AnimationMixer实现变形动画

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.AnimationMixer 动画…

【Linux】指令 + 重定向操作

Linux基本指令 一.Linux基本指令1.mv&#xff08;重要&#xff09;2.cat3.more和less&#xff08;重要&#xff09;4.head和tail5.date6.cal7.find&#xff08;重要&#xff09; 二.Linux相关知识点1. Linux系统中&#xff1a;一切皆文件2. 重定向操作1. 输出重定向2. 追加重定…

SpringBoot源码解析(四):解析应用参数args

SpringBoot源码系列文章 SpringBoot源码解析(一)&#xff1a;SpringApplication构造方法 SpringBoot源码解析(二)&#xff1a;引导上下文DefaultBootstrapContext SpringBoot源码解析(三)&#xff1a;启动开始阶段 SpringBoot源码解析(四)&#xff1a;解析应用参数args 目录…

Vue3.0 + Ts:动态设置style样式 ts 报错

error TS2322: Type ‘{ width: string; left: string; ‘background-color’: unknown; ‘z-index’: number; }’ is not assignable to type ‘StyleValue’ 在 vue3.0 ts 项目中&#xff0c;动态设置样式报错 在 Vue 3 TypeScript 项目中&#xff0c;当你使用 :style 绑…

跨平台WPF框架Avalonia教程 十六

SelectableTextBlock 可选文本块 SelectableTextBlock 块是一个用于显示文本的标签&#xff0c;允许选择和复制文本。它可以显示多行&#xff0c;并且可以完全控制所使用的字体。 有用的属性​ 您可能最常使用这些属性&#xff1a; 属性描述SelectionStart当前选择的起始字…

【MySQL】库的基础操作入门指南

&#x1f351;个人主页&#xff1a;Jupiter. &#x1f680; 所属专栏&#xff1a;MySQL入门指南&#xff1a;从零开始的数据库之旅 欢迎大家点赞收藏评论&#x1f60a; 目录 ☁创建数据库语法说明&#xff1a; 创建数据库案例 &#x1f308;字符集和校验规则查看系统默认字符集…