首页 > 其他分享 >设计模式---- 工厂模式

设计模式---- 工厂模式

时间:2024-09-17 14:34:37浏览次数:1  
标签:return 创建 factory 工厂 ---- func 设计模式 type

工厂模式
工厂模式是一种创建型设计模式,它的主要目的是将对象的创建过程与对象的使用过程分离。工厂模式通过引入工厂类或者工厂方法,隐藏对象创建的复杂性,使得代码更加灵活、可扩展。工厂模式的使用场景主要在于:当我们需要对创建的对象进行封装或延迟创建时,工厂模式是一个很好的选择。

工厂模式的设计基于面向对象设计原则,尤其是开闭原则(Open-Closed Principle,OCP),即对扩展开放,对修改关闭。这意味着我们可以扩展现有系统中的产品类型,而不需要修改现有的代码结构。

工厂模式有三种主要类型,每种类型有其适用的场景和优缺点:

  1. 简单工厂模式(Simple Factory Pattern)
    概念
    简单工厂模式也被称为静态工厂方法(Static Factory Method)模式,它通过一个单一的工厂类来负责创建不同类型的对象。简单工厂模式将对象的创建逻辑集中在一个工厂类中,由工厂类根据传递的参数决定创建哪一种具体的对象。

适用场景
• 当需要创建的对象类型较少,并且可以通过条件判断来决定实例化哪一种具体类型时。
• 客户端不关心具体对象的创建过程,只需要得到对象。
优点
• 工厂类封装了对象的创建逻辑,客户端不需要了解对象创建的细节,只需要提供必要的参数。
• 客户端代码和具体产品类解耦,降低代码的复杂度。
缺点
• 工厂类的职责过重,如果需要增加新的产品类型,必须修改工厂类的代码,违反了“开闭原则”。
• 一旦产品种类过多,工厂类会变得难以维护。
示例代码(Go语言实现)
package main

import "fmt"

// 定义产品接口
type Animal interface {
Speak() string
}

// 具体产品:Dog
type Dog struct{}

func (d Dog) Speak() string {
return "Woof!"
}

// 具体产品:Cat
type Cat struct{}

func (c Cat) Speak() string {
return "Meow!"
}

// 简单工厂类
type AnimalFactory struct{}

// 创建产品实例的方法
func (af AnimalFactory) CreateAnimal(animalType string) Animal {
if animalType == "dog" {
return Dog{}
} else if animalType == "cat" {
return Cat{}
}
return nil
}

func main() {
factory := AnimalFactory{}

dog := factory.CreateAnimal("dog")
fmt.Println(dog.Speak()) // 输出: Woof!

cat := factory.CreateAnimal("cat")
fmt.Println(cat.Speak()) // 输出: Meow!

}
2. 工厂方法模式(Factory Method Pattern)
概念
工厂方法模式通过定义一个创建对象的接口,将对象的创建延迟到子类中。每个子类负责创建自己特定的对象。工厂方法模式解决了简单工厂模式中工厂类不断膨胀的问题,能够更灵活地扩展新的产品类型。

适用场景
• 当系统中的产品种类较多,且可能会频繁增加时,适合使用工厂方法模式。
• 需要通过子类来决定实例化哪个具体类时,使用工厂方法模式。
优点
• 遵循了“开闭原则”:增加新产品时,不需要修改已有的工厂类,而是增加新的具体工厂类。
• 客户端不需要知道哪个具体工厂被使用,客户端代码依赖于抽象工厂接口。
缺点
• 对于每个新的产品都需要创建一个具体的工厂类,这会增加系统的复杂度。
示例代码(Go语言实现)
package main

import "fmt"

// 产品接口
type Animal interface {
Speak() string
}

// 具体产品:Dog
type Dog struct{}

func (d Dog) Speak() string {
return "Woof!"
}

// 具体产品:Cat
type Cat struct{}

func (c Cat) Speak() string {
return "Meow!"
}

// 工厂接口
type AnimalFactory interface {
CreateAnimal() Animal
}

// 具体工厂:DogFactory
type DogFactory struct{}

func (df DogFactory) CreateAnimal() Animal {
return Dog{}
}

// 具体工厂:CatFactory
type CatFactory struct{}

func (cf CatFactory) CreateAnimal() Animal {
return Cat{}
}

func main() {
var factory AnimalFactory

factory = DogFactory{}
dog := factory.CreateAnimal()
fmt.Println(dog.Speak()) // 输出: Woof!

factory = CatFactory{}
cat := factory.CreateAnimal()
fmt.Println(cat.Speak()) // 输出: Meow!

}
工厂方法模式的设计思路
在工厂方法模式中,工厂的实现类和产品的实现类是成对出现的。每个工厂类专注于创建一个具体的产品。这样避免了一个工厂类变得过于臃肿,同时也使得系统更容易扩展新类型的产品。

  1. 抽象工厂模式(Abstract Factory Pattern)
    概念
    抽象工厂模式用于创建一族相关的对象,而不仅仅是一个具体的产品。抽象工厂模式为多个产品等级结构提供了一个统一的接口,客户端可以通过这个接口来创建一族相关的产品,而不需要指定这些产品的具体类。

适用场景
• 当系统需要创建一系列相关产品时,且客户端需要使用这些相关产品的组合。
• 当系统的产品对象分为多个等级结构(如不同风格的家具:维多利亚风格、现代风格等)。
优点
• 抽象工厂模式封装了对象创建的逻辑,客户端只需要通过工厂接口获取一组相关的对象,而不需要了解具体的类。
• 易于扩展。增加一个新的产品族时,只需添加一个新的工厂类即可。
缺点
• 如果需要支持新的产品种类,所有的工厂类都需要修改,违反了开闭原则。
• 产品族的复杂度高,系统会引入更多的类和接口。
示例代码(Go语言实现)
package main

import "fmt"

// 定义产品接口1:Chair
type Chair interface {
HasLegs() int
}

// 定义产品接口2:Sofa
type Sofa interface {
SitOn() string
}

// 具体产品:VictorianChair
type VictorianChair struct{}

func (vc VictorianChair) HasLegs() int {
return 4
}

// 具体产品:ModernChair
type ModernChair struct{}

func (mc ModernChair) HasLegs() int {
return 3
}

// 具体产品:VictorianSofa
type VictorianSofa struct{}

func (vs VictorianSofa) SitOn() string {
return "Sitting on Victorian Sofa"
}

// 具体产品:ModernSofa
type ModernSofa struct{}

func (ms ModernSofa) SitOn() string {
return "Sitting on Modern Sofa"
}

// 抽象工厂接口
type FurnitureFactory interface {
CreateChair() Chair
CreateSofa() Sofa
}

// 具体工厂:VictorianFactory
type VictorianFactory struct{}

func (vf VictorianFactory) CreateChair() Chair {
return VictorianChair{}
}

func (vf VictorianFactory) CreateSofa() Sofa {
return VictorianSofa{}
}

// 具体工厂:ModernFactory
type ModernFactory struct{}

func (mf ModernFactory) CreateChair() Chair {
return ModernChair{}
}

func (mf ModernFactory) CreateSofa() Sofa {
return ModernSofa{}
}

func main() {
var factory FurnitureFactory

factory = VictorianFactory{}
chair1 := factory.CreateChair()
sofa1 := factory.CreateSofa()
fmt.Println(chair1.HasLegs())   // 输出: 4
fmt.Println(sofa1.SitOn())      // 输出: Sitting on Victorian Sofa

factory = ModernFactory{}
chair2 := factory.CreateChair()
sofa2 := factory.CreateSofa()
fmt.Println(chair2.HasLegs())   // 输出: 3
fmt.Println(sofa2.SitOn())      // 输出: Sitting on Modern Sofa

}
抽象工厂模式的设计思路
抽象工厂模式将工厂接口提升到一个更高的抽象层次,它可以创建一系列相关的对象。通过引入产品族的概念,抽象工厂模式使得不同风格或系列的产品可以一起使用,而不会引入互不兼容的问题。

工厂模式的常见实际用处

  1. 简单工厂模式的实际应用
    场景:
    • 工具类库或通用库的实现中,经常会使用简单工厂来管理工具对象的创建。
    • 在一些配置文件解析的场景中,简单工厂可以根据不同的文件类型(如 XML、JSON、YAML)创建对应的解析器对象。
    实例:
    假设你在开发一个数据库连接库,需要根据不同的数据库类型(如 MySQL、PostgreSQL、SQLite)创建不同的数据库连接对象。在这种场景下,你可以使用简单工厂来根据传入的参数(数据库类型)返回相应的数据库连接实例。

package main

import "fmt"

// 数据库连接接口
type Database interface {
Connect() string
}

// MySQL 数据库连接实现
type MySQL struct{}

func (m MySQL) Connect() string {
return "Connected to MySQL"
}

// PostgreSQL 数据库连接实现
type PostgreSQL struct{}

func (p PostgreSQL) Connect() string {
return "Connected to PostgreSQL"
}

// SQLite 数据库连接实现
type SQLite struct{}

func (s SQLite) Connect() string {
return "Connected to SQLite"
}

// 简单工厂类
type DatabaseFactory struct{}

func (df DatabaseFactory) CreateDatabase(dbType string) Database {
if dbType == "mysql" {
return MySQL{}
} else if dbType == "postgresql" {
return PostgreSQL{}
} else if dbType == "sqlite" {
return SQLite{}
}
return nil
}

func main() {
factory := DatabaseFactory{}

db := factory.CreateDatabase("mysql")
fmt.Println(db.Connect()) // 输出: Connected to MySQL

db = factory.CreateDatabase("postgresql")
fmt.Println(db.Connect()) // 输出: Connected to PostgreSQL

}
实际用途:
• 数据库驱动:不同类型的数据库连接通过简单工厂来创建。
• 文件格式解析器:可以根据文件格式(如JSON、XML)创建相应的解析器对象。
• 支付网关:可以根据支付类型(如支付宝、微信、信用卡)创建对应的支付处理对象。
2. 工厂方法模式的实际应用
场景:
• 插件系统:当系统需要支持不同类型的插件(例如不同格式的文件导入导出插件),可以使用工厂方法模式为每种插件定义对应的工厂。
• 日志框架:在日志记录框架中,可以使用工厂方法模式创建不同类型的日志记录器(如文件日志、数据库日志、控制台日志等)。
• 操作系统跨平台开发:可以根据不同的操作系统平台(如Windows、Linux、MacOS)使用工厂方法模式创建相应的平台依赖对象。
实例:
假设我们开发一个日志系统,系统需要支持不同类型的日志记录方式,比如文件日志、控制台日志等。通过工厂方法模式,每个日志记录器都有对应的工厂实现。

package main

import "fmt"

// 日志记录器接口
type Logger interface {
Log(message string)
}

// 文件日志记录器实现
type FileLogger struct{}

func (f FileLogger) Log(message string) {
fmt.Println("File logger:", message)
}

// 控制台日志记录器实现
type ConsoleLogger struct{}

func (c ConsoleLogger) Log(message string) {
fmt.Println("Console logger:", message)
}

// 日志记录器工厂接口
type LoggerFactory interface {
CreateLogger() Logger
}

// 文件日志记录器工厂
type FileLoggerFactory struct{}

func (f FileLoggerFactory) CreateLogger() Logger {
return FileLogger{}
}

// 控制台日志记录器工厂
type ConsoleLoggerFactory struct{}

func (c ConsoleLoggerFactory) CreateLogger() Logger {
return ConsoleLogger{}
}

func main() {
var factory LoggerFactory

// 使用文件日志记录器
factory = FileLoggerFactory{}
logger := factory.CreateLogger()
logger.Log("Logging to file") // 输出: File logger: Logging to file

// 使用控制台日志记录器
factory = ConsoleLoggerFactory{}
logger = factory.CreateLogger()
logger.Log("Logging to console") // 输出: Console logger: Logging to console

}
实际用途:
• 日志系统:可以根据配置选择控制台日志、文件日志、数据库日志等不同类型的日志输出。
• 消息队列:不同类型的消息队列(如RabbitMQ、Kafka)可以通过工厂方法模式创建。
• 跨平台应用:为不同操作系统创建特定的文件系统操作、UI组件等。
3. 抽象工厂模式的实际应用
场景:
• GUI框架:当我们需要为不同的操作系统或主题提供一套一致的用户界面组件时,可以使用抽象工厂模式创建一组相关的UI控件(如按钮、文本框等)。
• 数据库相关操作:当系统需要支持不同数据库系统(如MySQL、PostgreSQL)且需要创建一组相关的对象(如连接池、数据表操作类)时,抽象工厂可以统一创建一组相关的数据库操作对象。
• 游戏开发:在游戏中,不同种族或阵营的单位可以通过抽象工厂模式创建。比如创建一组“人族”或“兽族”的单位,包括战士、法师、建筑等。
实例:
假设我们在开发一个跨平台的图形用户界面(GUI)库,需要支持不同的操作系统(如Windows和MacOS),它们的按钮、文本框等组件外观不同。我们可以使用抽象工厂模式为每个平台提供一组相关的组件。

package main

import "fmt"

// 按钮接口
type Button interface {
Render()
}

// 文本框接口
type TextBox interface {
Render()
}

// Windows风格的按钮
type WindowsButton struct{}

func (wb WindowsButton) Render() {
fmt.Println("Rendering Windows Button")
}

// MacOS风格的按钮
type MacButton struct{}

func (mb MacButton) Render() {
fmt.Println("Rendering MacOS Button")
}

// Windows风格的文本框
type WindowsTextBox struct{}

func (wtb WindowsTextBox) Render() {
fmt.Println("Rendering Windows TextBox")
}

// MacOS风格的文本框
type MacTextBox struct{}

func (mtb MacTextBox) Render() {
fmt.Println("Rendering MacOS TextBox")
}

// 抽象工厂接口
type GUIFactory interface {
CreateButton() Button
CreateTextBox() TextBox
}

// Windows工厂
type WindowsFactory struct{}

func (wf WindowsFactory) CreateButton() Button {
return WindowsButton{}
}

func (wf WindowsFactory) CreateTextBox() TextBox {
return WindowsTextBox{}
}

// MacOS工厂
type MacFactory struct{}

func (mf MacFactory) CreateButton() Button {
return MacButton{}
}

func (mf MacFactory) CreateTextBox() TextBox {
return MacTextBox{}
}

func main() {
var factory GUIFactory

// 创建Windows风格的组件
factory = WindowsFactory{}
button := factory.CreateButton()
textBox := factory.CreateTextBox()
button.Render()    // 输出: Rendering Windows Button
textBox.Render()   // 输出: Rendering Windows TextBox

// 创建MacOS风格的组件
factory = MacFactory{}
button = factory.CreateButton()
textBox = factory.CreateTextBox()
button.Render()    // 输出: Rendering MacOS Button
textBox.Render()   // 输出: Rendering MacOS TextBox

}
实际用途:
• 跨平台UI库:创建不同操作系统或不同风格的用户界面组件。
• 数据库操作层:创建一组与数据库相关的对象(如连接、查询器、事务管理器)。
• 游戏开发:创建不同种族或阵营的游戏单位及建筑。
工厂模式在实际开发中的优点

  1. 代码解耦:工厂模式将对象的创建过程封装起来,客户端无需关心对象的具体实现细节,减少了模块之间的依赖性,使得代码更易于维护和修改。
  2. 提高代码的可扩展性:通过工厂方法或抽象工厂模式,可以轻松地扩展新的产品类型或产品家族,而无需修改客户端代码。
  3. 遵循开闭原则:工厂模式符合开闭原则(Open-Closed Principle),即对扩展开放,对修改关闭。新产品可以通过添加新工厂来实现,而不需要修改已有的工厂代码。
  4. 简化对象创建过程:在一些复杂对象的创建过程中,工厂模式可以封装这些复杂的逻辑,简化客户端的使用,特别适合创建需要多个步骤或依赖的对象。
    工厂模式总结
  5. 定义:工厂模式是一种创建型设计模式,主要用于将对象的创建逻辑与使用逻辑分离,通过工厂类或方法来创建对象。
  6. 主要类型:
    • 简单工厂模式:通过一个工厂类创建不同类型的对象,适用于对象种类较少、变化不大的场景。
    • 工厂方法模式:定义一个用于创建对象的接口,每个子类实现不同的创建逻辑,适合需要频繁扩展产品类型的场景。
    • 抽象工厂模式:提供创建一组相关或互相依赖对象的接口,适用于产品族(如一组UI组件或数据库操作对象)的创建。
  7. 实际用途:
    • 数据库驱动、文件格式解析器、支付系统等场景适合简单工厂模式。
    • 日志系统、消息队列、跨平台开发适合工厂方法模式。
    • 跨平台UI组件库、数据库操作系统、游戏开发适合抽象工厂模式。
  8. 优点:
    • 解耦:将对象创建和使用分离,减少模块之间的依赖。
    • 可扩展性强:通过扩展工厂类或方法轻松引入新产品,符合开闭原则。
    • 简化复杂对象创建:封装创建复杂对象的细节,简化客户端代码。
  9. 应用场景: 工厂模式适用于需要灵活创建对象、支持不同产品类型或家族、或处理复杂对象创建逻辑的场景。

标签:return,创建,factory,工厂,----,func,设计模式,type
From: https://www.cnblogs.com/zhifwu/p/18417155

相关文章

  • macOS Sequoia 15 发布,iPhone 镜像、密码应用程序、窗口平铺更新等带来全新体验
    macOSSequoia15.0(24A335)正式版ISO、IPSW、PKG下载2024年9月17日凌晨1点TimCook领导的Apple今天发布了macOS15Sequoia正式版,这是专为Mac运行的操作系统的最新版本。macOSSequoia是一个免费更新,可以在2018年及更高版本的MacBookPro、2020年及更高......
  • C语言基础
    注释代码的方式选中需要注释的代码,然后ctrl+/即可注释代码//printf("%d\n",strlen(arr));ctrl+/这个也是注释需要注释的代码在那行代码前面加//也可以注释代码//scanf("%d%d",&a,&b);//注释代码输入输出函数介绍了C语言中的标准输入输出函数,以及使用方式。scanf函数scanf......
  • leetCode2:两数相加(链表)
    题目:给你两个非空的链表,表示两个非负的整数。它们每位数字都是按照逆序的方式存储的,并且每个节点只能存储一位数字。请你将两个数相加,并以相同形式返回一个表示和的链表。你可以假设除了数字0之外,这两个数都不会以0开头。思路:遍历两个链表,逐位相加,还要加上进位结......
  • C++信奥老师解一本通题 1370:最小函数值(minval)
    ​【题目描述】有n个函数,分别为F1,F2,...,Fn。定义Fi(x)=Ai*x*x+Bi*x+Ci(x∈N∗)。给定这些Ai、Bi和Ci,请求出所有函数的所有函数值中最小的mm个(如有重复的要输出多个)。【输入】第一行输入两个正整数n和m。以下nn行每行三个正整数,其中第ii行的三个数分别位Ai、Bi和Ci输入数......
  • VUE框架CLI组件化组件解绑事件实现------VUE框架
    <template> <div> <!--内置函数的实现步骤--> <!--提供事件源,给事件源绑定事件,编写回调函数,将回调函数和事件进行绑定--> <!--等待事件的触发,事件触发执行回调函数--> <!--组件的自定义事件实现步骤--> <button@click="Hello()">你好</button> <!--给Us......
  • 【高中数学/极值/基本不等式】已知正实数x,y满足xy+2x+3y=42 则xy+5x+4y的最小值为?
    【问题】已知正实数x,y满足xy+2x+3y=42则xy+5x+4y的最小值为?【出处】《解题卡壳怎么办--高中数学解题智慧剖析》P38页第5题余继光、苏德矿著 【解答】由xy+2x+3y=42得(x+3)(y+2)-6=42再得(x+3)(y+2)=48设a=x+3,b=y+2xy+5x+4y=(x+4)(y+5)-20=(a+1)(b+3)-20=ab+3a+b+3-20=48+3a+......
  • 云词典——基于TCP和sqlite3实现
    项目需求 功能描述      仿照有道云词典功能,实现一个自己的云词典。自行定义项目名,最终可以体现到简历中。 效果参考功能矩阵功能模块功能点功能点描述优先级备注客户端注册可实现新用户的注册功能A登录支持用户登录校验,错误给出......
  • 反DDD模式之关系型数据库
    本文书接上回《图穷匕见-所有反DDD模式都是垃圾》,关注公众号(老肖想当外语大佬)获取信息:最新文章更新;DDD框架源码(.NET、Java双平台);加群畅聊,建模分析、技术实现交流;视频和直播在B站。背景我在与开发者交流关于DDD的建模思路时,往往会遇到一个难题,就是不少经验丰富的开发者,总是带着技......
  • c语言_day6(完结)
    目录函数格式:函数的声明函数的调用:函数名(实参)形参和实参区别:函数传参值传递地址传递数组传递开辟堆区空间string函数族strcpystrncpystrcatstrcmp递归函数结构体格式:结构体变量赋值访问重定义typedef结构体数组初始化结构体指针赋值:大小结构体......
  • 基于django+vue高校毕业论文管理系统【开题报告+程序+论文】-计算机毕设
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着高等教育规模的持续扩大,毕业论文作为衡量学生综合素质与专业能力的重要环节,其管理工作日益复杂。传统的手工管理方式已难以满足当前高......