Menu
CoddyTech

工厂模式

本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 87 课,共 107 课。

工厂模式将对象创建委托给单独的函数或方法,让你无需暴露创建逻辑即可创建实例。与控制实例数量的单例模式不同,工厂模式侧重于根据输入参数灵活地创建对象。

在 Go 中,工厂通常是一个返回接口类型的函数,让你可以通过统一的 API 创建不同的具体类型:

type Notifier interface {
    Send(message string) string
}

type EmailNotifier struct{}
type SMSNotifier struct{}

func (e EmailNotifier) Send(message string) string {
    return "Email: " + message
}

func (s SMSNotifier) Send(message string) string {
    return "SMS: " + message
}

func NewNotifier(notifierType string) Notifier {
    switch notifierType {
    case "email":
        return EmailNotifier{}
    case "sms":
        return SMSNotifier{}
    default:
        return EmailNotifier{}
    }
}

工厂函数 NewNotifier 封装了要创建哪种具体类型的决策。客户端代码只使用 Notifier 接口,无需了解具体实现:

notifier := NewNotifier("sms")
result := notifier.Send("Hello!")  // "SMS: Hello!"

当你需要根据运行时条件创建对象、集中处理复杂的初始化逻辑,或轻松添加新类型而不修改客户端代码时,这种模式尤其有用。只需添加一个实现该接口的新结构体,并更新工厂函数。

challenge icon

挑战

简单

让我们使用工厂模式构建一个文档转换系统!你将创建一个工厂,根据目标格式生成不同的文档转换器,让客户端代码通过统一的接口使用任意转换器。

你将把代码分成两个文件:

  • converter.go:定义转换器接口和具体实现。

    创建一个 Converter 接口,其中包含一个方法 Convert(content string) string,该方法接收文档内容并返回转换后的输出。

    实现三种转换器类型:

    • PDFConverter:它的 Convert 方法返回 PDF: [content]
    • HTMLConverter:它的 Convert 方法返回 HTML: <p>[content]</p>
    • MarkdownConverter:它的 Convert 方法返回 MD: # [content]

    创建一个工厂函数 NewConverter(format string) Converter,根据格式字符串(pdf、html 或 markdown)返回对应的转换器。对于任何无法识别的格式,默认返回一个 PDFConverter。

  • main.go:使用工厂创建转换器并处理文档。

    读取格式类型和文档内容。使用工厂创建对应的转换器,然后转换内容并打印结果。

将提供以下输入:

  • 第 1 行:格式类型(pdf、html、markdown 或其他内容)
  • 第 2 行:要转换的文档内容

例如,给定:

html
Welcome to Go Programming

你的输出应为:

HTML: <p>Welcome to Go Programming</p>

再例如,给定:

markdown
Chapter One

你的输出应为:

MD: # Chapter One

再例如,给定:

pdf
Annual Report 2024

你的输出应为:

PDF: Annual Report 2024

再例如,给定:

docx
Meeting Notes

你的输出应为:

PDF: Meeting Notes

注意,主代码不需要了解具体的转换器类型。它只需向工厂请求一个转换器,然后使用接口即可。这样一来,之后添加新格式就很容易,而且无需更改客户端代码!

亲手试试

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// 读取格式类型
	scanner.Scan()
	format := scanner.Text()
	
	// 读取文档内容
	scanner.Scan()
	content := scanner.Text()
	
	// TODO:使用工厂创建合适的转换器
	// TODO:转换内容并打印结果
	
	fmt.Println(result)
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器