go设计模式
1. Factory 工厂
场景
根据配置创建不同实现:例如存储(内存/文件/S3)、AI provider(OpenAI/豆包/DeepSeek)等。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| package factory
import ( "errors" "fmt" "sync" )
type Storage interface { Put(key, val string) error Get(key string) (string, error) }
type MemoryStorage struct { mu sync.RWMutex m map[string]string }
func NewMemoryStorage() *MemoryStorage { return &MemoryStorage{m: map[string]string{}} } func (s *MemoryStorage) Put(key, val string) error { s.mu.Lock() defer s.mu.Unlock() s.m[key] = val return nil } func (s *MemoryStorage) Get(key string) (string, error) { s.mu.RLock() defer s.mu.RUnlock() v, ok := s.m[key] if !ok { return "", errors.New("not found") } return v, nil }
type FileStorage struct { path string }
func NewFileStorage(path string) *FileStorage { return &FileStorage{path: path} } func (s *FileStorage) Put(key, val string) error { return fmt.Errorf("write to file %s: %s=%s (demo)", s.path, key, val) } func (s *FileStorage) Get(key string) (string, error) { return "", fmt.Errorf("read from file %s key=%s (demo)", s.path, key) }
func NewStorage(kind string) (Storage, error) { switch kind { case "memory": return NewMemoryStorage(), nil case "file": return NewFileStorage("./data.txt"), nil default: return nil, fmt.Errorf("unknown storage kind: %s", kind) } }
|
用法
1 2 3 4
| s, _ := factory.NewStorage("memory") _ = s.Put("hello", "world") v, _ := s.Get("hello") println(v)
|
2. Abstract Factory 抽象工厂
场景
一整套组件一起切换:不同云厂商(对象存储 + 队列 + 数据库),不同 UI 主题等。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
| package abstractfactory
import "fmt"
type ObjectStore interface{ PutObject(name string) error } type Queue interface{ Publish(topic string, msg []byte) error } type DB interface{ Exec(sql string) error }
type CloudFactory interface { ObjectStore() ObjectStore Queue() Queue DB() DB }
type awsObjectStore struct{} func (o awsObjectStore) PutObject(name string) error { fmt.Println("aws s3 put:", name); return nil }
type awsQueue struct{} func (q awsQueue) Publish(topic string, msg []byte) error { fmt.Println("aws sqs pub:", topic, string(msg)); return nil }
type awsDB struct{} func (d awsDB) Exec(sql string) error { fmt.Println("aws rds exec:", sql); return nil }
type AWSFactory struct{} func (AWSFactory) ObjectStore() ObjectStore { return awsObjectStore{} } func (AWSFactory) Queue() Queue { return awsQueue{} } func (AWSFactory) DB() DB { return awsDB{} }
type aliyunObjectStore struct{} func (o aliyunObjectStore) PutObject(name string) error { fmt.Println("aliyun oss put:", name); return nil }
type aliyunQueue struct{} func (q aliyunQueue) Publish(topic string, msg []byte) error { fmt.Println("aliyun mq pub:", topic, string(msg)); return nil }
type aliyunDB struct{} func (d aliyunDB) Exec(sql string) error { fmt.Println("aliyun rds exec:", sql); return nil }
type AliyunFactory struct{} func (AliyunFactory) ObjectStore() ObjectStore { return aliyunObjectStore{} } func (AliyunFactory) Queue() Queue { return aliyunQueue{} } func (AliyunFactory) DB() DB { return aliyunDB{} }
|
用法
1 2 3 4
| var f abstractfactory.CloudFactory = abstractfactory.AWSFactory{} _ = f.ObjectStore().PutObject("a.png") _ = f.Queue().Publish("events", []byte("hi")) _ = f.DB().Exec("select 1")
|
3. Builder / Functional Options 构建器
场景
构造参数很多、默认值多、可选项多:HTTP Client、业务 SDK、机器人配置。
Go 最常用写法:Functional Options(比传统 Builder 更地道)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package options
import ( "net/http" "time" )
type Client struct { baseURL string timeout time.Duration retry int http *http.Client }
type Option func(*Client)
func WithBaseURL(u string) Option { return func(c *Client) { c.baseURL = u } } func WithTimeout(d time.Duration) Option { return func(c *Client) { c.timeout = d c.http.Timeout = d } } func WithRetry(n int) Option { return func(c *Client) { c.retry = n } }
func NewClient(opts ...Option) *Client { c := &Client{ baseURL: "https://example.com", timeout: 10 * time.Second, retry: 0, http: &http.Client{Timeout: 10 * time.Second}, } for _, opt := range opts { opt(c) } return c }
|
用法
1 2 3 4 5 6
| c := options.NewClient( options.WithBaseURL("https://api.xxx.com"), options.WithTimeout(3*time.Second), options.WithRetry(2), ) _ = c
|
4. Singleton 单例
场景
全局唯一:日志器、配置加载器、连接池(注意测试难度/全局状态污染)。
代码(sync.Once)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package singleton
import ( "log" "os" "sync" )
type Logger struct{ *log.Logger }
var ( once sync.Once ins *Logger )
func GetLogger() *Logger { once.Do(func() { ins = &Logger{Logger: log.New(os.Stdout, "[app] ", log.LstdFlags|log.Lshortfile)} }) return ins }
|
用法
1
| singleton.GetLogger().Println("hello")
|
5. Adapter 适配器
场景
第三方库接口与你项目不一致:你希望统一成 Send(ctx, msg),但第三方只有 Do(req)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package adapter
import ( "context" "fmt" )
type Sender interface { Send(ctx context.Context, msg string) error }
type ThirdPartyClient struct{} func (c *ThirdPartyClient) Do(payload []byte) error { fmt.Println("third-party do:", string(payload)) return nil }
type ThirdPartyAdapter struct { c *ThirdPartyClient }
func NewThirdPartyAdapter(c *ThirdPartyClient) *ThirdPartyAdapter { return &ThirdPartyAdapter{c: c} }
func (a *ThirdPartyAdapter) Send(ctx context.Context, msg string) error { _ = ctx return a.c.Do([]byte(msg)) }
|
用ive:用法
1 2
| s := adapter.NewThirdPartyAdapter(&adapter.ThirdPartyClient{}) _ = s.Send(context.Background(), "hi")
|
6. Decorator / Middleware 装饰器
场景
给服务叠加能力:日志、指标、鉴权、限流、缓存。
本质就是 “在接口外面再包一层”(Go middleware 的核心)。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package decorator
import ( "context" "fmt" "time" )
type Service interface { Handle(ctx context.Context, input string) (string, error) }
type BaseService struct{} func (BaseService) Handle(ctx context.Context, input string) (string, error) { return "ok:" + input, nil }
type Logging struct{ next Service } func (l Logging) Handle(ctx context.Context, input string) (string, error) { start := time.Now() out, err := l.next.Handle(ctx, input) fmt.Println("log cost:", time.Since(start), "err:", err) return out, err }
type Timeout struct{ next Service; d time.Duration } func (t Timeout) Handle(ctx context.Context, input string) (string, error) { ctx, cancel := context.WithTimeout(ctx, t.d) defer cancel() return t.next.Handle(ctx, input) }
type Wrap func(Service) Service
func WithLogging() Wrap { return func(s Service) Service { return Logging{next: s} } } func WithTimeout(d time.Duration) Wrap { return func(s Service) Service { return Timeout{next: s, d: d} } } func Build(base Service, wraps ...Wrap) Service { s := base for i := len(wraps) - 1; i >= 0; i-- { s = wraps[i](s) } return s }
|
用法
1 2 3 4 5 6 7
| svc := decorator.Build( decorator.BaseService{}, decorator.WithLogging(), decorator.WithTimeout(200*time.Millisecond), ) out, _ := svc.Handle(context.Background(), "hello") println(out)
|
7. Proxy 代理
场景
控制访问:缓存、权限、熔断、延迟加载。
和装饰器很像,但 Proxy 更强调“控制访问/保护对象”。
代码(缓存代理)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| package proxy
import ( "errors" "sync" )
type UserRepo interface { GetUserName(id int64) (string, error) }
type DBRepo struct{} func (DBRepo) GetUserName(id int64) (string, error) { if id == 0 { return "", errors.New("invalid id") } return "user-from-db", nil }
type CacheRepo struct { next UserRepo mu sync.RWMutex cache map[int64]string }
func NewCacheRepo(next UserRepo) *CacheRepo { return &CacheRepo{next: next, cache: map[int64]string{}} }
func (c *CacheRepo) GetUserName(id int64) (string, error) { c.mu.RLock() if v, ok := c.cache[id]; ok { c.mu.RUnlock() return v, nil } c.mu.RUnlock()
v, err := c.next.GetUserName(id) if err != nil { return "", err }
c.mu.Lock() c.cache[id] = v c.mu.Unlock() return v, nil }
|
8. Facade 外观
场景
把复杂子系统封装成简单 API:支付/风控/通知/记账等。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| package facade
import "fmt"
type Risk struct{} func (Risk) Check(orderID string) error { fmt.Println("risk check:", orderID); return nil }
type Charge struct{} func (Charge) Pay(orderID string) error { fmt.Println("charge pay:", orderID); return nil }
type Ledger struct{} func (Ledger) Record(orderID string) error { fmt.Println("ledger record:", orderID); return nil }
type Notify struct{} func (Notify) Send(orderID string) error { fmt.Println("notify:", orderID); return nil }
type PaymentFacade struct { r Risk c Charge l Ledger n Notify }
func NewPaymentFacade() *PaymentFacade { return &PaymentFacade{r: Risk{}, c: Charge{}, l: Ledger{}, n: Notify{}} }
func (p *PaymentFacade) Pay(orderID string) error { if err := p.r.Check(orderID); err != nil { return err } if err := p.c.Pay(orderID); err != nil { return err } if err := p.l.Record(orderID); err != nil { return err } return p.n.Send(orderID) }
|
9. Strategy 策略
场景
同一个目标,多种算法可替换:调度、评分、路由、排序。
代码(调度策略)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| package strategy
import ( "math/rand" "sync/atomic" "time" )
type Picker interface { Pick(nodes []string) string }
type RandomPicker struct{} func (RandomPicker) Pick(nodes []string) string { rand.Seed(time.Now().UnixNano()) return nodes[rand.Intn(len(nodes))] }
type RoundRobin struct{ idx uint64 } func (r *RoundRobin) Pick(nodes []string) string { i := atomic.AddUint64(&r.idx, 1) return nodes[int(i)%len(nodes)] }
type Scheduler struct{ p Picker } func NewScheduler(p Picker) *Scheduler { return &Scheduler{p: p} } func (s *Scheduler) Next(nodes []string) string { return s.p.Pick(nodes) }
|
用法
1 2 3 4 5 6
| nodes := []string{"a","b","c"} s1 := strategy.NewScheduler(strategy.RandomPicker{}) println(s1.Next(nodes))
s2 := strategy.NewScheduler(&strategy.RoundRobin{}) println(s2.Next(nodes))
|
10. Observer 发布订阅
场景
组件解耦:事件驱动(消息事件、订单事件、机器人事件)。
Go 常见实现:channel 广播 / event bus。
代码(轻量 EventBus)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| package observer
import ( "context" "sync" )
type Event struct { Topic string Data any }
type Bus struct { mu sync.RWMutex subs map[string][]chan Event }
func NewBus() *Bus { return &Bus{subs: map[string][]chan Event{}} }
func (b *Bus) Subscribe(topic string, buf int) <-chan Event { ch := make(chan Event, buf) b.mu.Lock() b.subs[topic] = append(b.subs[topic], ch) b.mu.Unlock() return ch }
func (b *Bus) Publish(e Event) { b.mu.RLock() chs := append([]chan Event(nil), b.subs[e.Topic]...) b.mu.RUnlock()
for _, ch := range chs { select { case ch <- e: default: } } }
func (b *Bus) Consume(ctx context.Context, ch <-chan Event, fn func(Event)) { for { select { case <-ctx.Done(): return case e := <-ch: fn(e) } } }
|
11. Command 命令
场景
把请求封装为命令:可注册、可排队、可扩展(CLI、管理指令、机器人命令)。
代码(命令注册表)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| package command
import ( "context" "fmt" )
type Command interface { Name() string Execute(ctx context.Context, args []string) error }
type Registry struct { cmds map[string]Command } func NewRegistry() *Registry { return &Registry{cmds: map[string]Command{}} }
func (r *Registry) Register(c Command) { r.cmds[c.Name()] = c } func (r *Registry) Run(ctx context.Context, name string, args []string) error { c, ok := r.cmds[name] if !ok { return fmt.Errorf("unknown command: %s", name) } return c.Execute(ctx, args) }
type Help struct{} func (Help) Name() string { return "help" } func (Help) Execute(ctx context.Context, args []string) error { fmt.Println("available: help, ping (demo)") return nil }
|
12. State 状态机
场景
流程驱动:订单/任务/会话。
重点:限制非法状态转移。
代码(订单状态)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package state
import "fmt"
type Status string
const ( Created Status = "created" Paid Status = "paid" Shipped Status = "shipped" Done Status = "done" )
type Order struct { ID string Status Status }
func (o *Order) Pay() error { if o.Status != Created { return fmt.Errorf("cannot pay when status=%s", o.Status) } o.Status = Paid return nil }
func (o *Order) Ship() error { if o.Status != Paid { return fmt.Errorf("cannot ship when status=%s", o.Status) } o.Status = Shipped return nil }
func (o *Order) Finish() error { if o.Status != Shipped { return fmt.Errorf("cannot finish when status=%s", o.Status) } o.Status = Done return nil }
|
13. Chain of Responsibility 责任链
场景
规则链/审批流/过滤器:黑名单 → 频控 → 额度 → 通过。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package chain
import "fmt"
type Context struct { UserID int64 Score int }
type Handler interface { SetNext(Handler) Handle(*Context) error }
type Base struct{ next Handler } func (b *Base) SetNext(n Handler) { b.next = n } func (b *Base) Next(c *Context) error { if b.next == nil { return nil } return b.next.Handle(c) }
type Blacklist struct{ Base; blocked map[int64]bool } func NewBlacklist(blocked map[int64]bool) *Blacklist { return &Blacklist{blocked: blocked} } func (h *Blacklist) Handle(c *Context) error { if h.blocked[c.UserID] { return fmt.Errorf("blocked user: %d", c.UserID) } return h.Next(c) }
type ScoreGate struct{ Base; min int } func NewScoreGate(min int) *ScoreGate { return &ScoreGate{min: min} } func (h *ScoreGate) Handle(c *Context) error { if c.Score < h.min { return fmt.Errorf("score too low: %d < %d", c.Score, h.min) } return h.Next(c) }
func BuildChain(hs ...Handler) Handler { for i := 0; i < len(hs)-1; i++ { hs[i].SetNext(hs[i+1]) } return hs[0] }
|
用法
1 2 3 4 5 6
| bl := chain.NewBlacklist(map[int64]bool{2: true}) sg := chain.NewScoreGate(60) root := chain.BuildChain(bl, sg)
err := root.Handle(&chain.Context{UserID: 1, Score: 80}) println(err == nil)
|
练习建议(让你真的“会用”)
把这些模式串成一个小项目(很适合你做的群聊机器人):
- Factory + Options:初始化机器人(不同平台适配器、超时、重试)
- Adapter:把 OneBot/NapCat 的消息结构适配成统一
Message 接口
- Observer:EventBus 分发事件(message/join/leave)
- Strategy:回复策略(冷淡/活跃/仅@回复)
- State:会话状态(沉默/插话/闲聊/严肃)
- Decorator:日志/限流/敏感词过滤装饰链
- Command:
/help /mute /stats
- Chain:风控/规则链(黑名单、频控、相似度过滤)