【golang长途旅行第38站】工厂模式

工厂模式

工厂模式是一种非常常用的创建型设计模式,它提供了一种创建对象的方式,而无需向客户端暴露对象的具体创建逻辑。在 Go 语言中,由于其本身没有构造函数和类的概念,工厂模式显得尤为重要和自然。

核心思想

核心思想是:​定义一个用于创建对象的接口(或函数),让子类(或具体实现)决定实例化哪一个类(或结构体)​。这样,客户端代码只依赖于对象的接口,而不是具体的实现,从而实现了依赖关系的解耦。

为什么在 Go 中使用工厂模式?

  1. ​隐藏创建细节​:当对象的创建过程非常复杂(例如需要依赖配置、环境变量、或者需要一系列初始化步骤)时,工厂模式可以将这些复杂性封装起来,为客户端提供一个简洁的创建接口。

  2. ​依赖接口而非实现​:客户端代码只需要知道对象提供的接口,而不需要关心其具体的实现类型。这使得代码更灵活,更容易替换和维护。

  3. ​控制实例化​:工厂函数可以控制返回的实例。例如,它可以返回一个单例、一个池化后的对象,或者根据条件返回不同子类的实例。

  4. ​命名的好处​:Go 的结构体没有构造函数。像 NewMyStruct()这样的工厂函数比 &MyStruct{}更富有表现力,尤其当初始化参数很多时,一个良好的函数名可以清晰地表达创建意图。

工厂模式的三种形式

在 Go 中,工厂模式主要有三种常见的实现形式:

  1. 简单工厂模式 (Simple Factory)
    这是最基础的形式,通常就是一个简单的函数,根据传入的参数返回不同的对象实例。
    package main

import "fmt"

// 1. 定义接口

type Logger interface {

Log(message string)

}

// 2. 定义具体实现:文件日志

type FileLogger struct{}

func (f *FileLogger) Log(message string) {

fmt.Printf("Logging to file: %s\n", message)

}

// 3. 定义具体实现:标准输出日志

type StdoutLogger struct{}

func (s *StdoutLogger) Log(message string) {

fmt.Printf("Logging to stdout: %s\n", message)

}

// 4. 工厂函数:核心所在

func NewLogger(logType string) Logger {

switch logType {

case "file":

return &FileLogger{}

case "stdout":

fallthrough // 落到 default

default:

return &StdoutLogger{}

}

}

// 客户端代码

func main() {

// 客户端只需要知道 Logger 接口和工厂函数

// 而不需要知道 FileLogger 或 StdoutLogger 的具体存在

var logger Logger

复制代码
logger = NewLogger("file")
logger.Log("This goes to a file.") // Output: Logging to file: This goes to a file.

logger = NewLogger("stdout")
logger.Log("This goes to stdout.") // Output: Logging to stdout: This goes to stdout.

}

  1. 工厂方法模式 (Factory Method)

它为每一类产品提供一个独立的工厂函数,从而避免了在简单工厂中使用条件判断。

​示例:创建不同的数据库连接

package main

import "fmt"

// 数据库连接接口

type DatabaseConnector interface {

Connect()

}

// 具体实现:MySQL

type MySQLConnector struct{}

func (m *MySQLConnector) Connect() {

fmt.Println("Connected to MySQL database.")

}

// 工厂函数 for MySQL

func NewMySQLConnector() DatabaseConnector {

return &MySQLConnector{}

}

// 具体实现:PostgreSQL

type PostgreSQLConnector struct{}

func (p *PostgreSQLConnector) Connect() {

fmt.Println("Connected to PostgreSQL database.")

}

// 工厂函数 for PostgreSQL

func NewPostgreSQLConnector() DatabaseConnector {

return &PostgreSQLConnector{}

}

// 客户端代码

func main() {

// 根据需要调用不同的工厂函数

var dbConn DatabaseConnector

复制代码
dbConn = NewMySQLConnector()
dbConn.Connect() // Output: Connected to MySQL database.

dbConn = NewPostgreSQLConnector()
dbConn.Connect() // Output: Connected to PostgreSQL database.

}

  1. 抽象工厂模式 (Abstract Factory)

这是最复杂的形式,用于创建一系列相关或依赖的对象家族,而不需要指定它们具体的类。

​示例:创建跨平台的 UI 组件

package main

import "fmt"

// ------ 抽象产品接口 ------

type Button interface {

Render()

}

type TextBox interface {

Display()

}

// ------ 抽象工厂接口 ------

type UIFactory interface {

CreateButton() Button

CreateTextBox() TextBox

}

// ------ 具体产品 & 具体工厂 for Windows ------

type WinButton struct{}

func (w WinButton) Render() {

fmt.Println("Rendering a Windows-style button.")

}

type WinTextBox struct{}

func (w WinTextBox) Display() {

fmt.Println("Displaying a Windows-style textbox.")

}

type WinFactory struct{}

func (w WinFactory) CreateButton() Button {

return WinButton{}

}

func (w WinFactory) CreateTextBox() TextBox {

return WinTextBox{}

}

// ------ 具体产品 & 具体工厂 for macOS ------

type MacButton struct{}

func (m MacButton) Render() {

fmt.Println("Rendering a macOS-style button.")

}

type MacTextBox struct{}

func (m MacTextBox) Display() {

fmt.Println("Displaying a macOS-style textbox.")

}

type MacFactory struct{}

func (m MacFactory) CreateButton() Button {

return MacButton{}

}

func (m MacFactory) CreateTextBox() TextBox {

return MacTextBox{}

}

// ------ 客户端代码 ------

// 获取一个工厂,这个工厂能创建一整套风格一致的UI组件

func GetUIFactory(platform string) UIFactory {

switch platform {

case "windows":

return WinFactory{}

case "mac":

return MacFactory{}

default:

panic("unsupported platform")

}

}

func main() {

// 根据运行环境决定使用哪个工厂

factory := GetUIFactory("mac") // 切换为 "windows" 试试

复制代码
// 用同一个工厂创建一套协调的UI组件
button := factory.CreateButton()
textbox := factory.CreateTextBox()

button.Render()   // Output: Rendering a macOS-style button.
textbox.Display() // Output: Displaying a macOS-style textbox.

}

相关推荐
绝无仅有4 小时前
某互联网大厂的面试go语言从基础到实战的经验和总结
后端·面试·github
Dxy12393102164 小时前
Dockerfile文件常用配置详解
开发语言·docker
小蒜学长4 小时前
基于SpringBoot+Vue的健身房管理系统的设计与实现(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端
MATLAB代码顾问4 小时前
MATLAB可以实现的各种智能算法
开发语言·matlab
这里有鱼汤4 小时前
你以为 FastAPI 足够强?其实 Litestar 能让你的项目更轻量高效
后端·python
菜鸟谢5 小时前
windows vscode go 编译速度慢问题
后端
王伯安呢5 小时前
Java开发环境配置入门指南
java·开发语言·jvm·eclipse·环境搭建·新手
Victor3565 小时前
Redis(51)如何监控Redis哨兵的状态?
后端
·前路漫漫亦灿灿5 小时前
C++-类型转换
开发语言·c++