在Go语言项目里,当系统需要生成成千上万个属性大部分相同的对象时,如果每次都新建实例,会迅速推高内存占用并增加垃圾回收负担。享元模式的核心是把对象中可共享的部分抽离出来统一管理,让多个上下文重复利用同一份数据,从而减少重复分配。

什么是享元模式
享元模式属于结构型设计模式,目的是通过共享技术有效支持大量细粒度对象的复用。它将对象状态分为内部状态与外部状态:内部状态可共享且不会随环境改变,外部状态由调用方传入。Golang中常用struct保存内部状态,用map充当享元工厂。
基础实现示例
下面定义一个表示字体样式的享元对象,并通过工厂复用:
package main
import "fmt"
// Font 内部状态可共享
type Font struct {
Name string
Size int
}
// FontFactory 享元工厂
type FontFactory struct {
pool map[string]*Font
}
func NewFontFactory() *FontFactory {
return &FontFactory{pool: make(map[string]*Font)}
}
func (f *FontFactory) GetFont(name string, size int) *Font {
key := fmt.Sprintf("%s_%d", name, size)
if font, ok := f.pool[key]; ok {
return font
}
font := &Font{Name: name, Size: size}
f.pool[key] = font
return font
}
func main() {
factory := NewFontFactory()
f1 := factory.GetFont("Arial", 12)
f2 := factory.GetFont("Arial", 12)
fmt.Println(f1 == f2) // true,复用同一对象
}
结合sync.Pool优化临时对象
对于生命周期短但创建频繁的对象,可配合标准库sync.Pool进一步降低分配次数:
package main
import (
"sync"
)
type Request struct {
UserID int
Data []byte
}
var reqPool = sync.Pool{
New: func() interface{} {
return &Request{}
},
}
func acquireRequest() *Request {
return reqPool.Get().(*Request)
}
func releaseRequest(r *Request) {
r.UserID = 0
r.Data = nil
reqPool.Put(r)
}
使用注意点
- 仅当对象创建成本高或数量庞大时才引入享元,否则会增加复杂度。
- 共享数据必须不可变,避免多协程并发修改引发错误。
- 外部状态不要存入享元对象,应由调用方自行维护。
小结
通过提取可共享状态、使用map或sync.Pool管理复用,Golang能明显削减内存分配。合理运用享元模式,可让服务在高频调用场景中保持更低延迟与更稳定表现。