当前位置: 首页 > news >正文

工厂模式与策略模式(golang示例)

一、工厂模式简介

工厂模式是一种创建型设计模式,主要用于封装对象的创建过程。通过使用工厂模式,客户端代码无需直接实例化对象,而是通过工厂类来创建对象。这样可以将对象的创建与使用分离,从而提高代码的灵活性。

1.1 工厂模式的实现

示例场景:假设我们需要创建不同类型的日志记录器(如文件日志记录器、控制台日志记录器)。

package mainimport ("fmt"
)// 产品接口
type Logger interface {Log(message string)
}// 具体产品类:文件日志记录器
type FileLogger struct{}func (f *FileLogger) Log(message string) {fmt.Printf("FileLogger: %s\n", message)
}// 具体产品类:控制台日志记录器
type ConsoleLogger struct{}func (c *ConsoleLogger) Log(message string) {fmt.Printf("ConsoleLogger: %s\n", message)
}// 工厂类
type LoggerFactory struct{}func (lf *LoggerFactory) CreateLogger(loggerType string) Logger {if loggerType == "file" {return &FileLogger{}} else if loggerType == "console" {return &ConsoleLogger{}}return nil
}func main() {factory := &LoggerFactory{}logger1 := factory.CreateLogger("file")logger1.Log("This is a file log message.")logger2 := factory.CreateLogger("console")logger2.Log("This is a console log message.")
}

输出

FileLogger: This is a file log message.
ConsoleLogger: This is a console log message.
1.2 适用场景
  • 系统需要独立于产品类的创建和使用。
  • 系统需要通过统一的接口创建一系列相关或依赖的对象。
  • 需要在运行时根据某些条件决定创建哪个类的实例。
1.3 工厂模式的优缺点
  • 优点

    • 提供对象创建的封装,使代码更加灵活,便于维护和扩展。
    • 通过工厂类可以很容易地扩展和修改对象的创建过程。
  • 缺点

    • 随着产品类的增加,工厂类可能变得复杂,难以管理。
二、策略模式简介

策略模式是一种行为型设计模式,旨在定义一系列可互换的算法或行为,使得它们可以在运行时互相替换。通过使用策略模式,算法的实现被封装起来,客户端可以根据不同的需求选择不同的算法,而无需修改客户端代码。

2.1 策略模式的实现

示例场景:假设我们有一个支付系统,支持多种支付方式(如信用卡支付、微信支付、支付宝支付)。

package mainimport ("fmt"
)// 策略接口
type PaymentStrategy interface {Pay(amount float64)
}// 具体策略类:信用卡支付
type CreditCardPayment struct {CardNumber string
}func (c *CreditCardPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using Credit Card: %s\n", amount, c.CardNumber)
}// 具体策略类:微信支付
type WeChatPayment struct {WeChatID string
}func (w *WeChatPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using WeChat ID: %s\n", amount, w.WeChatID)
}// 具体策略类:支付宝支付
type AlipayPayment struct {AlipayID string
}func (a *AlipayPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using Alipay ID: %s\n", amount, a.AlipayID)
}// 上下文类
type PaymentContext struct {strategy PaymentStrategy
}func (p *PaymentContext) SetStrategy(strategy PaymentStrategy) {p.strategy = strategy
}func (p *PaymentContext) ExecutePay(amount float64) {if p.strategy == nil {fmt.Println("Payment strategy not set.")return}p.strategy.Pay(amount)
}func main() {context := &PaymentContext{}creditCard := &CreditCardPayment{CardNumber: "1234-5678-9012-3456"}context.SetStrategy(creditCard)context.ExecutePay(100.0)weChat := &WeChatPayment{WeChatID: "weixin_abc123"}context.SetStrategy(weChat)context.ExecutePay(200.0)alipay := &AlipayPayment{AlipayID: "alipay_xyz789"}context.SetStrategy(alipay)context.ExecutePay(300.0)
}

输出

Paid 100.00 using Credit Card: 1234-5678-9012-3456
Paid 200.00 using WeChat ID: weixin_abc123
Paid 300.00 using Alipay ID: alipay_xyz789
2.2 适用场景
  • 系统需要在不同的算法或行为之间进行切换,并且这些算法或行为可以互相替换。
  • 需要在运行时根据客户端的需求选择不同的策略或算法。
  • 避免使用大量的条件语句来选择不同的算法。
2.3 策略模式的优缺点
  • 优点

    • 策略的分离使得算法可以独立于客户端的变化,并且可以轻松添加或更改策略。
    • 避免了大量的条件语句,使代码更加清晰、易于维护。
  • 缺点

    • 客户端必须知道所有可用的策略,并且需要选择合适的策略,这可能增加代码的复杂性。
三、工厂模式与策略模式的区别

尽管工厂模式和策略模式在设计思想上有相似之处,但它们的应用场景和解决的问题却完全不同。

  1. 意图和用途

    • 工厂模式:关注的是对象的创建。它通过封装对象的创建过程,避免客户端直接实例化对象,并允许系统在不修改客户端代码的情况下扩展新的产品类型。
    • 策略模式:关注的是行为的选择。它通过将不同的算法或行为封装在不同的策略类中,使得客户端可以在运行时自由选择和切换行为。
  2. 参与者

    • 工厂模式:包含工厂类、产品接口/抽象类以及具体产品类,工厂类负责创建产品对象。
    • 策略模式:包含策略接口、具体策略类和上下文类,上下文类负责在运行时选择和执行具体的策略。
  3. 使用场景

    • 工厂模式:适用于系统需要独立于产品类的创建和使用,并且需要通过统一的方式创建一系列相关或依赖的对象时。
    • 策略模式:适用于系统需要在不同算法或行为之间进行切换,并且这些算法或行为可以互相替换的场景。
  4. 代码结构

    • 工厂模式:通常涉及到多个工厂类和产品类,工厂类的复杂度可能会随着产品类型的增加而增加。
    • 策略模式:通常包含一个策略接口及其多个具体实现类,策略类的增加不会影响上下文类的实现。
四、综合对比与选择

在实际开发中,工厂模式和策略模式可以独立使用,也可以结合使用,视具体需求而定。例如,可以使用工厂模式来创建策略对象,从而实现策略模式的灵活扩展。

示例:结合工厂模式创建策略对象

package mainimport ("fmt"
)// 策略接口
type PaymentStrategy interface {Pay(amount float64)
}// 具体策略类:信用卡支付
type CreditCardPayment struct {CardNumber string
}func (c *CreditCardPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using Credit Card: %s\n", amount, c.CardNumber)
}// 具体策略类:微信支付
type WeChatPayment struct {WeChatID string
}func (w *WeChatPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using WeChat ID: %s\n", amount, w.WeChatID)
}// 具体策略类:支付宝支付
type AlipayPayment struct {AlipayID string
}func (a *AlipayPayment) Pay(amount float64) {fmt.Printf("Paid %.2f using Alipay ID: %s\n", amount, a.AlipayID)
}// 策略工厂
type PaymentFactory struct{}func (pf *PaymentFactory) CreatePayment(strategyType string) PaymentStrategy {if strategyType == "creditcard" {return &CreditCardPayment{CardNumber: "1234-5678-9012-3456"}} else if strategyType == "wechat" {return &WeChatPayment{WeChatID: "weixin_abc123"}} else if strategyType == "alipay" {return &AlipayPayment{AlipayID: "alipay_xyz789"}}return nil
}// 上下文类
type PaymentContext struct {strategy PaymentStrategy
}func (p *PaymentContext) SetStrategy(strategy PaymentStrategy) {p.strategy = strategy
}func (p *PaymentContext) ExecutePay(amount float64) {if p.strategy == nil {fmt.Println("Payment strategy not set.")return}p.strategy.Pay(amount)
}func main() {factory := &PaymentFactory{}context := &PaymentContext{}// 使用工厂创建策略creditCard := factory.CreatePayment("creditcard")context.SetStrategy(creditCard)context.ExecutePay(150.0)weChat := factory.CreatePayment("wechat")context.SetStrategy(weChat)context.ExecutePay(250.0)alipay := factory.CreatePayment("alipay")context.SetStrategy(alipay)context.ExecutePay(350.0)
}

输出

Paid 150.00 using Credit Card: 1234-5678-9012-3456
Paid 250.00 using WeChat ID: weixin_abc123
Paid 350.00 using Alipay ID: alipay_xyz789

在这个示例中,PaymentFactory 结合了工厂模式和策略模式,通过工厂方法创建不同的支付策略对象,使得策略的创建和使用更加灵活和解耦。

五、总结

工厂模式和策略模式是软件设计中非常常见的两种模式,它们分别关注对象的创建和行为的选择。在实际开发中,理解它们的意图和使用场景对于编写高质量的代码至关重要。

  • 工厂模式适用于需要对对象的创建过程进行封装的场景,通过提供统一的接口来创建对象,避免了客户端直接依赖具体类,从而提高了代码的灵活性和可扩展性。

  • 策略模式适用于需要在不同算法或行为之间进行切换的场景,通过将算法封装在不同的策略类中,使得客户端可以根据需求灵活选择和切换行为,提升了代码的可维护性和可扩展性。

通过合理地应用这两种模式,甚至将它们结合使用,可以大大提高代码的可维护性和可扩展性,使得系统能够更好地应对未来的变化和需求。理解和掌握这两种设计模式,将为您的开发工作带来更多的灵活性和效率。


希望这篇博客能够帮助您更好地理解工厂模式和策略模式的区别,以及如何在实际项目中应用它们。如果您有任何问题或建议,欢迎在评论区留言讨论!

相关文章:

工厂模式与策略模式(golang示例)

一、工厂模式简介 工厂模式是一种创建型设计模式,主要用于封装对象的创建过程。通过使用工厂模式,客户端代码无需直接实例化对象,而是通过工厂类来创建对象。这样可以将对象的创建与使用分离,从而提高代码的灵活性。 1.1 工厂模…...

批量视频如何做成一个二维码(分步骤教程)

原创教程,阿酷TONY,2024.9.11,湖南长沙 批量视频如何做成一个二维码(分步骤教程),场景应用: 1. 一批视频需要按组分类,生成一个二维码,实现扫一个二维码,观看…...

OpengGL教程(三)---使用VAO和VBO方式绘制三角形

本章参考官方教程:learnopengl-cn VertexShader.glsl #version 330 core layout(location 0) in vec3 position; layout(location 1) in vec3 color; uniform mat4 projection; // 投影矩阵 out vec4 ourColor; void main() {gl_Position projection * vec4(p…...

【单片机开发】单片机常用开发工具

【前言】 在嵌入式系统领域,单片机(Microcontroller, MCU)作为核心组件,广泛应用于智能家居、工业控制、汽车电子等众多领域。而单片机开发工具,则是开发者们实现创意、解决问题的重要助手。本文主要讲述目前主流的单…...

一、计算机网络的体系结构

1.1 计算机网络的组成 1)从组成部分上分为:硬件、软件、协议。硬件是指主机、通信链路、交换设备和通信处理机组曾。软件包括各种实现资源共享的软件以及各种软件工具(如网络操作系统、邮件收发程序、FTP程序、聊天软件)。 2&…...

C语言补习课——文件篇

来源:黑马程序员 第157讲 C语言操作文件概述 读取文件:输入流 写文件:输出流 读写的方向判断取决与参照,一般我们站在程序的角度判断读写方向。 第158讲 路径 基本概念 路径就是指文件在电脑中的位置,eg&#xf…...

【可测试性实践】C++ 单元测试代码覆盖率统计入门

引言 最近在调研C工程怎么做单元测试和代码覆盖率统计,由于我们工程有使用Boost库,尝试使用Boost.Test来实现单元测试并通过Gcov和Lcov来生成代码覆盖率报告。本文记录完整的搭建测试Demo,希望能带来一定参考。 常用C单测框架对比 特性Goo…...

C++笔记---list

1. list的介绍 list其实就是就是我们所熟知的链表(双向循环带头结点),但其是作为STL中的一个类模板而存在。 也就是说,list是可以用来存储任意类型数据的顺序表,既可以是内置类型,也可以是自定义类型&…...

JavaWeb开发中为什么Controller里面的方法是@RequestMapping?

在Java Web开发中,尤其是在使用Spring MVC框架时,RequestMapping注解被广泛应用于Controller层的方法上,这是因为RequestMapping是Spring MVC提供的一个核心注解,用于将HTTP请求映射到相应的处理器类或处理器方法上。通过这种方式…...

若依移动版使用微信小程序打开失败

现象 解决办法:删掉自带的appid...

精准控图工具 Concept Sliders:超好用的 控制 Lora 适配器

Concept Sliders 你有没有遇到这样的情况?你花费大量时间制作提示和寻找种子,以使用文本到图像模型生成所需的图像。但是,你还需要对生成图像中的属性强度(如眼睛大小或照明)进行更细致、更精细的控制。修改提示会破坏…...

【EI会议征稿通知】第四届材料工程与应用力学国际学术会议(ICMEAAE 2025)

第四届材料工程与应用力学国际学术会议(ICMEAAE 2025) 2025 4th International Conference on Materials Engineering and Applied Mechanics 本次会议将重点讨论材料科学、应用力学等领域的最新研究进展与发展趋势。会议旨在为国内外从事这些领域研究…...

Hadoop安全之Knox

Apache Knox 是一个 REST API 网关,为 Hadoop 集群提供安全的访问方式。Knox 提供了一层保护,简化了对 Hadoop 生态系统(如 HDFS、YARN、Hive、HBase 等)中各个组件的访问,并通过单点登录 (SSO)、认证、授权和审计功能…...

SprinBoot+Vue应急信息管理系统的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍:CSDN认证博客专家,CSDN平台Java领域优质…...

索尼研究的AI部门将与AI新加坡合作开发大型语言模型

索尼研究公司签署了一项合作协议,以帮助测试和优化东南亚语言一网通(SEA-LION)人工智能(AI)模型,重点关注印度语言。 索尼研究公司的AI部门将与负责开发AI新加坡(AISG)的公司合作&a…...

【OJ刷题】双指针问题

这里是阿川的博客,祝您变得更强 ✨ 个人主页:在线OJ的阿川 💖文章专栏:OJ刷题入门到进阶 🌏代码仓库: 写在开头 现在您看到的是我的结论或想法,但在这背后凝结了大量的思考、经验和讨论 目录 1…...

基于SpringBoot+Vue+MySQL的校园食堂订餐

系统展示 用户前台界面 管理员后台界面 系统背景 随着信息技术的飞速发展和互联网的普及,传统校园食堂的运作模式已难以满足现代学生日益增长的便捷性、个性化需求。学生们希望能够在忙碌的学习生活中,通过更加高效、便捷的方式完成就餐选择,…...

uniapp业务实现

uni.requset添加异常判断提示,以及加载动画 /*** 该函数用于发送网络请求获取数据* 请求失败时会弹出相应的错误提示* 请求成功时会检查返回的数据是否存在错误,并根据错误代码做出相应处理* 如果数据请求成功且无错误,则将返回的数据赋值给pets变量*/fu…...

Windows和Mac命令窗快速打开文件夹

Windows explorer . 和 macOS open . 命令详解 1. Windows explorer . explorer 是 Windows 上的文件资源管理器,用于通过命令行打开文件夹或文件。 常用命令格式: explorer [选项] [目标路径]. 表示当前目录,explorer . 打开当前工作目录…...

智能制造云平台---附源码79117

目 录 摘要 1 绪论 1.1 研究背景和意义 1.2开发技术 1.2.1 Flask框架 1.2.2 Python简介 1.2.3 MySQL数据库 1.3论文结构与章节安排 2系统分析 2.1 可行性分析 2.2总体设计原则 2.3 系统流程分析 2.3.1 用户登录流程 2.3.2 删除信息流程 2.4 系统角色分析 2.5 系…...

后进先出(LIFO)详解

LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子&#xff08…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

docker 部署发现spring.profiles.active 问题

报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

群晖NAS如何在虚拟机创建飞牛NAS

套件中心下载安装Virtual Machine Manager 创建虚拟机 配置虚拟机 飞牛官网下载 https://iso.liveupdate.fnnas.com/x86_64/trim/fnos-0.9.2-863.iso 群晖NAS如何在虚拟机创建飞牛NAS - 个人信息分享...

关于uniapp展示PDF的解决方案

在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项&#xff1a; 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库&#xff1a; npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...

Linux中《基础IO》详细介绍

目录 理解"文件"狭义理解广义理解文件操作的归类认知系统角度文件类别 回顾C文件接口打开文件写文件读文件稍作修改&#xff0c;实现简单cat命令 输出信息到显示器&#xff0c;你有哪些方法stdin & stdout & stderr打开文件的方式 系统⽂件I/O⼀种传递标志位…...

Linux 下 DMA 内存映射浅析

序 系统 I/O 设备驱动程序通常调用其特定子系统的接口为 DMA 分配内存&#xff0c;但最终会调到 DMA 子系统的dma_alloc_coherent()/dma_alloc_attrs() 等接口。 关于 dma_alloc_coherent 接口详细的代码讲解、调用流程&#xff0c;可以参考这篇文章&#xff0c;我觉得写的非常…...

【若依】框架项目部署笔记

参考【SpringBoot】【Vue】项目部署_no main manifest attribute, in springboot-0.0.1-sn-CSDN博客 多一个redis安装 准备工作&#xff1a; 压缩包下载&#xff1a;http://download.redis.io/releases 1. 上传压缩包&#xff0c;并进入压缩包所在目录&#xff0c;解压到目标…...

跨平台商品数据接口的标准化与规范化发展路径:淘宝京东拼多多的最新实践

在电商行业蓬勃发展的当下&#xff0c;多平台运营已成为众多商家的必然选择。然而&#xff0c;不同电商平台在商品数据接口方面存在差异&#xff0c;导致商家在跨平台运营时面临诸多挑战&#xff0c;如数据对接困难、运营效率低下、用户体验不一致等。跨平台商品数据接口的标准…...

GAN模式奔溃的探讨论文综述(一)

简介 简介:今天带来一篇关于GAN的,对于模式奔溃的一个探讨的一个问题,帮助大家更好的解决训练中遇到的一个难题。 论文题目:An in-depth review and analysis of mode collapse in GAN 期刊:Machine Learning 链接:...