11. 享元模式(Flyweight)
11. 享元模式(Flyweight)
问题:大量相似对象占用过多内存。
核心:把不变的部分(内在状态)共享,可变的部分(外在状态)外部传入。
class TextStyle {
constructor(
public readonly font: string,
public readonly size: number,
public readonly color: string,
) {}
}
class StyleFactory {
#cache: Map<string, TextStyle> = new Map();
getStyle(font: string, size: number, color: string): TextStyle {
const key = `${font}-${size}-${color}`;
let style = this.#cache.get(key);
if (!style) {
style = new TextStyle(font, size, color);
this.#cache.set(key, style);
}
return style;
}
}
const factory = new StyleFactory();
const s1 = factory.getStyle('Arial', 14, 'black');
const s2 = factory.getStyle('Arial', 14, 'black');
console.log(s1 === s2); // true — 共享同一个对象package flyweight
import "fmt"
type TextStyle struct {
Font string
Size int
Color string
}
type StyleFactory struct {
cache map[string]*TextStyle
}
func NewStyleFactory() *StyleFactory {
return &StyleFactory{cache: make(map[string]*TextStyle)}
}
func (f *StyleFactory) GetStyle(font string, size int, color string) *TextStyle {
key := fmt.Sprintf("%s-%d-%s", font, size, color)
if _, ok := f.cache[key]; !ok {
f.cache[key] = &TextStyle{Font: font, Size: size, Color: color}
}
return f.cache[key]
}实战场景
- 文本编辑器样式共享:成千上万个字符不必各自保存字体、字号、颜色,只共享同一份样式对象。
- 地图标记:大量点位共享图标、颜色、交互配置,坐标和业务 id 作为外部状态传入。
- 游戏粒子和子弹:纹理、模型、动画配置共享,位置、速度、生命周期由外部状态管理。
- 棋盘或网格单元:单元格的样式、类型、行为共享,当前坐标和状态单独存储。
- 图标资源池:同一个 SVG、图片或字体图标只加载一次,多个组件引用同一资源。
- 权限规则对象:大量用户共享同一组角色定义或策略模板,用户自己的角色绑定是外部状态。
- 表格单元格渲染:大数据表格中,渲染器、格式化器、校验器可以共享,具体值和行号外部传入。
- CAD 或设计工具:相同组件、符号、物料只保存一份定义,画布上的实例只保存位置、旋转、缩放。
- 编译器 token 类型:关键字、操作符、标识符类型等元信息共享,具体词面量和位置独立保存。
- 缓存池:颜色对象、正则表达式、格式化器、Intl formatter 等创建成本高且可复用的对象可以集中共享。