Skip to content

Go语言设计模式实战指南

引言

设计模式是软件开发中的最佳实践,本文将介绍Go语言中常用的设计模式及其实现。

创建型模式

单例模式

go
package singleton

import "sync"

type Singleton struct {
    data int
}

var instance *Singleton
var once sync.Once

func GetInstance() *Singleton {
    once.Do(func() {
        instance = &Singleton{data: 0}
    })
    return instance
}

工厂方法模式

go
package factory

type PaymentMethod interface {
    Pay(amount float64) string
}

type CashPayment struct{}

func (c *CashPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using cash", amount)
}

type CreditCardPayment struct{}

func (c *CreditCardPayment) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using credit card", amount)
}

func CreatePayment(method string) PaymentMethod {
    switch method {
    case "cash":
        return &CashPayment{}
    case "credit":
        return &CreditCardPayment{}
    default:
        return nil
    }
}

建造者模式

go
package builder

type Computer struct {
    CPU     string
    Memory  string
    Storage string
}

type ComputerBuilder struct {
    computer *Computer
}

func NewComputerBuilder() *ComputerBuilder {
    return &ComputerBuilder{computer: &Computer{}}
}

func (b *ComputerBuilder) SetCPU(cpu string) *ComputerBuilder {
    b.computer.CPU = cpu
    return b
}

func (b *ComputerBuilder) SetMemory(memory string) *ComputerBuilder {
    b.computer.Memory = memory
    return b
}

func (b *ComputerBuilder) SetStorage(storage string) *ComputerBuilder {
    b.computer.Storage = storage
    return b
}

func (b *ComputerBuilder) Build() *Computer {
    return b.computer
}

结构型模式

适配器模式

go
package adapter

type OldPrinter interface {
    Print(s string) string
}

type NewPrinter interface {
    PrintStored() string
}

type OldPrinterImpl struct{}

func (p *OldPrinterImpl) Print(s string) string {
    return fmt.Sprintf("Old Printer: %s", s)
}

type PrinterAdapter struct {
    OldPrinter
    text string
}

func (p *PrinterAdapter) PrintStored() string {
    return p.Print(p.text)
}

装饰器模式

go
package decorator

type Component interface {
    Operation() string
}

type ConcreteComponent struct{}

func (c *ConcreteComponent) Operation() string {
    return "ConcreteComponent"
}

type Decorator struct {
    component Component
}

func (d *Decorator) Operation() string {
    return d.component.Operation()
}

type ConcreteDecoratorA struct {
    Decorator
}

func (d *ConcreteDecoratorA) Operation() string {
    return fmt.Sprintf("ConcreteDecoratorA(%s)", d.Decorator.Operation())
}

行为型模式

观察者模式

go
package observer

type Observer interface {
    Update(message string)
}

type Subject interface {
    Register(observer Observer)
    Deregister(observer Observer)
    NotifyAll(message string)
}

type ConcreteSubject struct {
    observers []Observer
}

func (s *ConcreteSubject) Register(observer Observer) {
    s.observers = append(s.observers, observer)
}

func (s *ConcreteSubject) Deregister(observer Observer) {
    for i, obs := range s.observers {
        if obs == observer {
            s.observers = append(s.observers[:i], s.observers[i+1:]...)
            break
        }
    }
}

func (s *ConcreteSubject) NotifyAll(message string) {
    for _, observer := range s.observers {
        observer.Update(message)
    }
}

策略模式

go
package strategy

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCardStrategy struct {
    cardNumber string
}

func (c *CreditCardStrategy) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using credit card %s", amount, c.cardNumber)
}

type PayPalStrategy struct {
    email string
}

func (p *PayPalStrategy) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f using PayPal account %s", amount, p.email)
}

type PaymentContext struct {
    strategy PaymentStrategy
}

func (c *PaymentContext) SetStrategy(strategy PaymentStrategy) {
    c.strategy = strategy
}

func (c *PaymentContext) ExecutePayment(amount float64) string {
    return c.strategy.Pay(amount)
}

并发模式

工作池模式

go
package workerpool

type Job struct {
    ID       int
    Data     interface{}
    Result   chan interface{}
}

type Worker struct {
    ID      int
    JobChan chan Job
    Quit    chan bool
}

func NewWorker(id int, jobChan chan Job) *Worker {
    return &Worker{
        ID:      id,
        JobChan: jobChan,
        Quit:    make(chan bool),
    }
}

func (w *Worker) Start() {
    go func() {
        for {
            select {
            case job := <-w.JobChan:
                // 处理任务
                result := processJob(job)
                job.Result <- result
            case <-w.Quit:
                return
            }
        }
    }()
}

type Pool struct {
    Workers    []*Worker
    JobQueue   chan Job
    MaxWorkers int
}

func NewPool(maxWorkers int) *Pool {
    pool := &Pool{
        JobQueue:   make(chan Job),
        MaxWorkers: maxWorkers,
    }
    
    pool.Start()
    return pool
}

func (p *Pool) Start() {
    for i := 0; i < p.MaxWorkers; i++ {
        worker := NewWorker(i, p.JobQueue)
        p.Workers = append(p.Workers, worker)
        worker.Start()
    }
}

发布订阅模式

go
package pubsub

type PubSub struct {
    subscribers map[string][]chan interface{}
    mu         sync.RWMutex
}

func NewPubSub() *PubSub {
    return &PubSub{
        subscribers: make(map[string][]chan interface{}),
    }
}

func (ps *PubSub) Subscribe(topic string) chan interface{} {
    ps.mu.Lock()
    defer ps.mu.Unlock()
    
    ch := make(chan interface{}, 1)
    ps.subscribers[topic] = append(ps.subscribers[topic], ch)
    return ch
}

func (ps *PubSub) Publish(topic string, data interface{}) {
    ps.mu.RLock()
    defer ps.mu.RUnlock()
    
    if subscribers, ok := ps.subscribers[topic]; ok {
        for _, ch := range subscribers {
            go func(ch chan interface{}) {
                ch <- data
            }(ch)
        }
    }
}

实战应用

Web服务中间件

go
package middleware

type Middleware func(http.HandlerFunc) http.HandlerFunc

func Chain(f http.HandlerFunc, middlewares ...Middleware) http.HandlerFunc {
    for _, m := range middlewares {
        f = m(f)
    }
    return f
}

func Logging() Middleware {
    return func(f http.HandlerFunc) http.HandlerFunc {
        return func(w http.ResponseWriter, r *http.Request) {
            start := time.Now()
            defer func() {
                log.Printf(
                    "%s %s %v",
                    r.Method,
                    r.URL.Path,
                    time.Since(start),
                )
            }()
            f(w, r)
        }
    }
}

func Auth() Middleware {
    return func(f 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
            }
            f(w, r)
        }
    }
}

数据库连接池

go
package dbpool

type DBPool struct {
    connections chan *sql.DB
    maxConn    int
    connStr    string
}

func NewDBPool(maxConn int, connStr string) (*DBPool, error) {
    pool := &DBPool{
        connections: make(chan *sql.DB, maxConn),
        maxConn:    maxConn,
        connStr:    connStr,
    }
    
    for i := 0; i < maxConn; i++ {
        conn, err := sql.Open("mysql", connStr)
        if err != nil {
            return nil, err
        }
        pool.connections <- conn
    }
    
    return pool, nil
}

func (p *DBPool) GetConnection() *sql.DB {
    return <-p.connections
}

func (p *DBPool) ReleaseConnection(conn *sql.DB) {
    p.connections <- conn
}

最佳实践

  1. 选择合适的设计模式
  2. 避免过度设计
  3. 保持代码简洁
  4. 注重可测试性
  5. 考虑并发安全

总结

Go语言的设计模式实现既保持了传统设计模式的精髓,又充分利用了Go语言的特性。合理使用设计模式可以提高代码的可维护性和可扩展性。

参考资料

  1. Go设计模式
  2. Clean Architecture(Robert C. Martin)
  3. Head First设计模式

幸运的人用童年治愈一生,不幸的人用一生治愈童年 —— 强爸