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
}
最佳实践
- 选择合适的设计模式
- 避免过度设计
- 保持代码简洁
- 注重可测试性
- 考虑并发安全
总结
Go语言的设计模式实现既保持了传统设计模式的精髓,又充分利用了Go语言的特性。合理使用设计模式可以提高代码的可维护性和可扩展性。
参考资料
- Go设计模式
- Clean Architecture(Robert C. Martin)
- Head First设计模式