设计模式:Go 语言中的实践

学习 Go 语言中常用的设计模式,用 Go 的方式写出优雅、可维护的代码

设计模式:Go 语言中的实践

设计模式是软件开发中经过验证的解决方案。它们不是具体的代码,而是一种思路,帮助你解决特定场景下的常见问题。

但是,不同的语言有不同的特性,设计模式的实现方式也会有所不同。Go 语言没有类、继承、泛型(1.18 之前),这让很多传统的面向对象设计模式需要"Go 化"。

今天我们就来学习如何在 Go 中实现常用的设计模式,用 Go 的方式写出优雅的代码。

创建型模式

单例模式(Singleton)

确保一个类只有一个实例,并提供一个全局访问点。

在 Go 中,通常使用 sync.Once 来实现:

package main

import (
	"fmt"
	"sync"
)

type Database struct {
	conn string
}

var (
	instance *Database
	once     sync.Once
)

func GetDatabase() *Database {
	once.Do(func() {
		fmt.Println("创建数据库实例...")
		instance = &Database{
			conn: "mysql://localhost:3306/mydb",
		}
	})
	return instance
}

func (db *Database) Query(sql string) {
	fmt.Printf("执行查询: %s\n", sql)
}

func main() {
	db1 := GetDatabase()
	db2 := GetDatabase()
	
	// 两次调用返回同一个实例
	fmt.Println(db1 == db2)  // true
	
	db1.Query("SELECT * FROM users")
	db2.Query("SELECT * FROM posts")
}

输出:

创建数据库实例...
true
执行查询: SELECT * FROM users
执行查询: SELECT * FROM posts

“创建数据库实例…” 只打印了一次,说明 sync.Once 确保了初始化只执行一次。

工厂模式(Factory)

定义一个创建对象的接口,让子类决定实例化哪个类。

在 Go 中,没有继承,我们用接口 + 工厂函数来实现:

package main

import "fmt"

// Payment 支付接口
type Payment interface {
	Pay(amount float64) error
}

// Alipay 支付宝支付
type Alipay struct{}

func (a *Alipay) Pay(amount float64) error {
	fmt.Printf("使用支付宝支付 %.2f 元\n", amount)
	return nil
}

// WechatPay 微信支付
type WechatPay struct{}

func (w *WechatPay) Pay(amount float64) error {
	fmt.Printf("使用微信支付 %.2f 元\n", amount)
	return nil
}

// BankCard 银行卡支付
type BankCard struct{}

func (b *BankCard) Pay(amount float64) error {
	fmt.Printf("使用银行卡支付 %.2f 元\n", amount)
	return nil
}

// PaymentFactory 支付工厂
type PaymentFactory struct{}

func (f *PaymentFactory) CreatePayment(method string) (Payment, error) {
	switch method {
	case "alipay":
		return &Alipay{}, nil
	case "wechat":
		return &WechatPay{}, nil
	case "bankcard":
		return &BankCard{}, nil
	default:
		return nil, fmt.Errorf("不支持的支付方式: %s", method)
	}
}

func main() {
	factory := &PaymentFactory{}
	
	// 用户选择支付方式
	payment, err := factory.CreatePayment("alipay")
	if err != nil {
		fmt.Println("创建支付失败:", err)
		return
	}
	
	payment.Pay(100.50)
}

建造者模式(Builder)

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。

package main

import "fmt"

// HTTPRequest HTTP 请求
type HTTPRequest struct {
	Method  string
	URL     string
	Headers map[string]string
	Body    string
	Timeout int
}

// RequestBuilder 请求构建器
type RequestBuilder struct {
	request *HTTPRequest
}

func NewRequestBuilder() *RequestBuilder {
	return &RequestBuilder{
		request: &HTTPRequest{
			Headers: make(map[string]string),
			Timeout: 30,
		},
	}
}

func (b *RequestBuilder) Method(method string) *RequestBuilder {
	b.request.Method = method
	return b
}

func (b *RequestBuilder) URL(url string) *RequestBuilder {
	b.request.URL = url
	return b
}

func (b *RequestBuilder) Header(key, value string) *RequestBuilder {
	b.request.Headers[key] = value
	return b
}

func (b *RequestBuilder) Body(body string) *RequestBuilder {
	b.request.Body = body
	return b
}

func (b *RequestBuilder) Timeout(timeout int) *RequestBuilder {
	b.request.Timeout = timeout
	return b
}

func (b *RequestBuilder) Build() *HTTPRequest {
	return b.request
}

func main() {
	// 使用链式调用构建请求
	req := NewRequestBuilder().
		Method("POST").
		URL("https://api.example.com/users").
		Header("Content-Type", "application/json").
		Header("Authorization", "Bearer token123").
		Body(`{"name":"张三","age":25}`).
		Timeout(60).
		Build()
	
	fmt.Printf("Method: %s\n", req.Method)
	fmt.Printf("URL: %s\n", req.URL)
	fmt.Printf("Headers: %v\n", req.Headers)
	fmt.Printf("Body: %s\n", req.Body)
	fmt.Printf("Timeout: %d\n", req.Timeout)
}

结构型模式

装饰器模式(Decorator)

动态地给一个对象添加一些额外的职责。

Go 没有类继承,我们用组合和函数式编程来实现:

package main

import (
	"fmt"
	"net/http"
	"time"
)

// 基础处理器
func helloHandler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Hello, World!")
}

// 装饰器:日志
func loggingMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		start := time.Now()
		next(w, r)
		fmt.Printf("%s %s %v\n", r.Method, r.URL.Path, time.Since(start))
	}
}

// 装饰器:认证
func authMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		token := r.Header.Get("Authorization")
		if token == "" {
			http.Error(w, "Unauthorized", http.StatusUnauthorized)
			return
		}
		next(w, r)
	}
}

// 装饰器:CORS
func corsMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Access-Control-Allow-Origin", "*")
		next(w, r)
	}
}

// 组合多个装饰器
func chain(h http.HandlerFunc, middlewares ...func(http.HandlerFunc) http.HandlerFunc) http.HandlerFunc {
	for i := len(middlewares) - 1; i >= 0; i-- {
		h = middlewares[i](h)
	}
	return h
}

func main() {
	// 应用装饰器
	handler := chain(helloHandler,
		loggingMiddleware,
		authMiddleware,
		corsMiddleware,
	)
	
	http.HandleFunc("/", handler)
	
	fmt.Println("服务器启动在 :8080")
	http.ListenAndServe(":8080", nil)
}

适配器模式(Adapter)

将一个类的接口转换成客户希望的另外一个接口。

package main

import "fmt"

// Logger 我们期望的接口
type Logger interface {
	Info(msg string)
	Error(msg string)
}

// ThirdPartyLogger 第三方日志库(有不同的接口)
type ThirdPartyLogger struct{}

func (l *ThirdPartyLogger) LogInfo(msg string) {
	fmt.Printf("[INFO] %s\n", msg)
}

func (l *ThirdPartyLogger) LogError(msg string) {
	fmt.Printf("[ERROR] %s\n", msg)
}

// LoggerAdapter 适配器
type LoggerAdapter struct {
	thirdParty *ThirdPartyLogger
}

func NewLoggerAdapter() *LoggerAdapter {
	return &LoggerAdapter{
		thirdParty: &ThirdPartyLogger{},
	}
}

func (a *LoggerAdapter) Info(msg string) {
	a.thirdParty.LogInfo(msg)
}

func (a *LoggerAdapter) Error(msg string) {
	a.thirdParty.LogError(msg)
}

// 使用我们定义的接口
func processOrder(logger Logger) {
	logger.Info("开始处理订单")
	// ... 处理逻辑 ...
	logger.Info("订单处理完成")
}

func main() {
	// 使用适配器
	logger := NewLoggerAdapter()
	processOrder(logger)
}

行为型模式

策略模式(Strategy)

定义一系列算法,把它们一个个封装起来,并且使它们可相互替换。

package main

import "fmt"

// SortStrategy 排序策略接口
type SortStrategy interface {
	Sort(data []int) []int
}

// BubbleSort 冒泡排序
type BubbleSort struct{}

func (b *BubbleSort) Sort(data []int) []int {
	result := make([]int, len(data))
	copy(result, data)
	
	n := len(result)
	for i := 0; i < n-1; i++ {
		for j := 0; j < n-i-1; j++ {
			if result[j] > result[j+1] {
				result[j], result[j+1] = result[j+1], result[j]
			}
		}
	}
	return result
}

// QuickSort 快速排序
type QuickSort struct{}

func (q *QuickSort) Sort(data []int) []int {
	result := make([]int, len(data))
	copy(result, data)
	quickSort(result, 0, len(result)-1)
	return result
}

func quickSort(arr []int, low, high int) {
	if low < high {
		pivot := partition(arr, low, high)
		quickSort(arr, low, pivot-1)
		quickSort(arr, pivot+1, high)
	}
}

func partition(arr []int, low, high int) int {
	pivot := arr[high]
	i := low - 1
	
	for j := low; j < high; j++ {
		if arr[j] < pivot {
			i++
			arr[i], arr[j] = arr[j], arr[i]
		}
	}
	arr[i+1], arr[high] = arr[high], arr[i+1]
	return i + 1
}

// Sorter 使用策略的上下文
type Sorter struct {
	strategy SortStrategy
}

func NewSorter(strategy SortStrategy) *Sorter {
	return &Sorter{strategy: strategy}
}

func (s *Sorter) SetStrategy(strategy SortStrategy) {
	s.strategy = strategy
}

func (s *Sorter) Sort(data []int) []int {
	return s.strategy.Sort(data)
}

func main() {
	data := []int{64, 34, 25, 12, 22, 11, 90}
	
	// 使用冒泡排序
	sorter := NewSorter(&BubbleSort{})
	fmt.Println("冒泡排序:", sorter.Sort(data))
	
	// 切换到快速排序
	sorter.SetStrategy(&QuickSort{})
	fmt.Println("快速排序:", sorter.Sort(data))
}

观察者模式(Observer)

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知。

package main

import (
	"fmt"
	"sync"
)

// Event 事件
type Event struct {
	Type string
	Data interface{}
}

// Observer 观察者接口
type Observer interface {
	OnEvent(event Event)
}

// EventEmitter 事件发射器(被观察者)
type EventEmitter struct {
	observers map[string][]Observer
	mu        sync.RWMutex
}

func NewEventEmitter() *EventEmitter {
	return &EventEmitter{
		observers: make(map[string][]Observer),
	}
}

func (e *EventEmitter) On(eventType string, observer Observer) {
	e.mu.Lock()
	defer e.mu.Unlock()
	e.observers[eventType] = append(e.observers[eventType], observer)
}

func (e *EventEmitter) Emit(event Event) {
	e.mu.RLock()
	observers := e.observers[event.Type]
	e.mu.RUnlock()
	
	for _, observer := range observers {
		observer.OnEvent(event)
	}
}

// LoggerObserver 日志观察者
type LoggerObserver struct{}

func (l *LoggerObserver) OnEvent(event Event) {
	fmt.Printf("[LOG] 事件: %s, 数据: %v\n", event.Type, event.Data)
}

// MetricsObserver 指标观察者
type MetricsObserver struct {
	count int
}

func (m *MetricsObserver) OnEvent(event Event) {
	m.count++
	fmt.Printf("[METRICS] %s 事件计数: %d\n", event.Type, m.count)
}

// User 用户(被观察对象)
type User struct {
	ID    int
	Name  string
	Email string
	emitter *EventEmitter
}

func NewUser(emitter *EventEmitter) *User {
	return &User{emitter: emitter}
}

func (u *User) UpdateEmail(newEmail string) {
	oldEmail := u.Email
	u.Email = newEmail
	
	u.emitter.Emit(Event{
		Type: "user.email_changed",
		Data: map[string]interface{}{
			"user_id":    u.ID,
			"old_email":  oldEmail,
			"new_email":  newEmail,
		},
	})
}

func main() {
	emitter := NewEventEmitter()
	
	// 注册观察者
	logger := &LoggerObserver{}
	metrics := &MetricsObserver{}
	
	emitter.On("user.email_changed", logger)
	emitter.On("user.email_changed", metrics)
	
	// 触发事件
	user := NewUser(emitter)
	user.ID = 1
	user.Name = "张三"
	user.Email = "old@example.com"
	
	user.UpdateEmail("new@example.com")
}

责任链模式(Chain of Responsibility)

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。

package main

import "fmt"

// Request 请求
type Request struct {
	Type    string
	Amount  float64
	UserID  int
}

// Handler 处理器接口
type Handler interface {
	SetNext(handler Handler) Handler
	Handle(request *Request) bool
}

// BaseHandler 基础处理器
type BaseHandler struct {
	next Handler
}

func (h *BaseHandler) SetNext(handler Handler) Handler {
	h.next = handler
	return handler
}

func (h *BaseHandler) HandleNext(request *Request) bool {
	if h.next != nil {
		return h.next.Handle(request)
	}
	return false
}

// AuthHandler 认证处理器
type AuthHandler struct {
	BaseHandler
}

func (h *AuthHandler) Handle(request *Request) bool {
	if request.UserID == 0 {
		fmt.Println("认证失败:用户未登录")
		return false
	}
	fmt.Println("认证通过")
	return h.HandleNext(request)
}

// LimitHandler 限额处理器
type LimitHandler struct {
	BaseHandler
	limit float64
}

func (h *LimitHandler) Handle(request *Request) bool {
	if request.Amount > h.limit {
		fmt.Printf("限额检查失败:金额 %.2f 超过限额 %.2f\n", request.Amount, h.limit)
		return false
	}
	fmt.Println("限额检查通过")
	return h.HandleNext(request)
}

// RiskHandler 风控处理器
type RiskHandler struct {
	BaseHandler
}

func (h *RiskHandler) Handle(request *Request) bool {
	// 模拟风控检查
	if request.Amount > 10000 {
		fmt.Println("风控检查失败:金额过大")
		return false
	}
	fmt.Println("风控检查通过")
	return h.HandleNext(request)
}

// ProcessHandler 最终处理器
type ProcessHandler struct {
	BaseHandler
}

func (h *ProcessHandler) Handle(request *Request) bool {
	fmt.Printf("处理请求:类型=%s, 金额=%.2f, 用户=%d\n",
		request.Type, request.Amount, request.UserID)
	return true
}

func main() {
	// 构建责任链
	auth := &AuthHandler{}
	limit := &LimitHandler{limit: 50000}
	risk := &RiskHandler{}
	process := &ProcessHandler{}
	
	auth.SetNext(limit).SetNext(risk).SetNext(process)
	
	// 测试请求
	requests := []*Request{
		{Type: "transfer", Amount: 1000, UserID: 0},      // 未登录
		{Type: "transfer", Amount: 60000, UserID: 1},     // 超限额
		{Type: "transfer", Amount: 15000, UserID: 1},     // 风控失败
		{Type: "transfer", Amount: 5000, UserID: 1},      // 成功
	}
	
	for _, req := range requests {
		fmt.Printf("\n--- 处理请求: 金额=%.2f, 用户=%d ---\n", req.Amount, req.UserID)
		if auth.Handle(req) {
			fmt.Println("✅ 请求处理成功")
		} else {
			fmt.Println("❌ 请求处理失败")
		}
	}
}

Go 特有的模式

选项模式(Options Pattern)

这是 Go 社区非常流行的模式,用于处理可选参数:

package main

import (
	"fmt"
	"time"
)

// Server 服务器配置
type Server struct {
	Host         string
	Port         int
	ReadTimeout  time.Duration
	WriteTimeout time.Duration
	MaxConns     int
}

// Option 选项函数
type Option func(*Server)

// WithHost 设置主机
func WithHost(host string) Option {
	return func(s *Server) {
		s.Host = host
	}
}

// WithPort 设置端口
func WithPort(port int) Option {
	return func(s *Server) {
		s.Port = port
	}
}

// WithTimeout 设置超时
func WithTimeout(read, write time.Duration) Option {
	return func(s *Server) {
		s.ReadTimeout = read
		s.WriteTimeout = write
	}
}

// WithMaxConns 设置最大连接数
func WithMaxConns(maxConns int) Option {
	return func(s *Server) {
		s.MaxConns = maxConns
	}
}

// NewServer 创建服务器
func NewServer(options ...Option) *Server {
	// 默认值
	server := &Server{
		Host:         "localhost",
		Port:         8080,
		ReadTimeout:  30 * time.Second,
		WriteTimeout: 30 * time.Second,
		MaxConns:     1000,
	}
	
	// 应用选项
	for _, option := range options {
		option(server)
	}
	
	return server
}

func main() {
	// 使用默认值
	server1 := NewServer()
	fmt.Printf("Server 1: %s:%d\n", server1.Host, server1.Port)
	
	// 自定义配置
	server2 := NewServer(
		WithHost("0.0.0.0"),
		WithPort(9090),
		WithTimeout(60*time.Second, 60*time.Second),
		WithMaxConns(5000),
	)
	fmt.Printf("Server 2: %s:%d (max=%d)\n",
		server2.Host, server2.Port, server2.MaxConns)
}

Worker Pool 模式

package main

import (
	"fmt"
	"sync"
	"time"
)

type Job struct {
	ID      int
	Payload string
}

type Result struct {
	JobID  int
	Output string
}

func worker(id int, jobs <-chan Job, results chan<- Result, wg *sync.WaitGroup) {
	defer wg.Done()
	
	for job := range jobs {
		// 模拟处理
		time.Sleep(100 * time.Millisecond)
		
		result := Result{
			JobID:  job.ID,
			Output: fmt.Sprintf("Worker %d processed: %s", id, job.Payload),
		}
		results <- result
	}
}

func main() {
	const (
		numWorkers = 5
		numJobs    = 20
	)
	
	jobs := make(chan Job, numJobs)
	results := make(chan Result, numJobs)
	
	var wg sync.WaitGroup
	
	// 启动 workers
	for i := 1; i <= numWorkers; i++ {
		wg.Add(1)
		go worker(i, jobs, results, &wg)
	}
	
	// 发送任务
	for i := 1; i <= numJobs; i++ {
		jobs <- Job{ID: i, Payload: fmt.Sprintf("Task %d", i)}
	}
	close(jobs)
	
	// 等待所有 worker 完成
	go func() {
		wg.Wait()
		close(results)
	}()
	
	// 收集结果
	for result := range results {
		fmt.Println(result.Output)
	}
}

小结

今天我们学习了 Go 语言中的设计模式:

创建型模式:

  • 单例模式(sync.Once
  • 工厂模式(接口 + 工厂函数)
  • 建造者模式(链式调用)

结构型模式:

  • 装饰器模式(函数组合)
  • 适配器模式(组合)

行为型模式:

  • 策略模式(接口 + 上下文)
  • 观察者模式(事件发射器)
  • 责任链模式(链式处理器)

Go 特有模式:

  • 选项模式(函数选项)
  • Worker Pool(goroutine 池)

设计模式不是银弹,不要为了用模式而用模式。选择最适合当前场景的方案,写出简洁、可维护的代码。

练习时间

  1. 实现代理模式:为远程服务调用添加缓存和重试
  2. 实现命令模式:构建一个支持撤销的操作历史
  3. 实现状态模式:构建一个订单状态机
  4. 实现访问者模式:为 AST(抽象语法树)添加不同的操作

我们下篇见!👋


参考资料:

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页