Что это такое
Паттерн Flyweight экономит память, когда программа хранит тысячи похожих объектов: тяжёлая общая часть сохраняется один раз, и на неё все ссылаются, а каждый объект хранит только свою небольшую уникальную часть.
Лесу из 10 000 деревьев не нужно 10 000 текстур — ему нужны 2 вида деревьев и 10 000 крошечных записей (x, y, вид).
Пример: лес с общими видами
getKind() выдаёт общие объекты видов из Map, создавая каждый только при первом запросе. Каждое дерево хранит лишь позицию и ссылку.
Много деревьев, мало видов
Деревьев четыре, но создаём вид печатается только дважды — дуб и сосна существуют по одному разу, каким бы большим ни стал лес. Две последние строки: посажено деревьев: 4 и сохранено видов: 2.
Вывод: программа на TypeScript и захваченный вывод
// Тяжёлая общая часть — создаётся один раз для каждого вида.
class TreeKind {
readonly name: string
readonly texture: string
constructor(name: string) {
this.name = name
this.texture = name + ".png"
}
}
const kinds = new Map<string, TreeKind>()
function getKind(name: string): TreeKind {
const found = kinds.get(name)
if (found !== undefined) {
return found
}
console.log("создаём вид:", name)
const kind = new TreeKind(name)
kinds.set(name, kind)
return kind
}
// Лёгкая часть для каждого дерева: позиция и ссылка.
type Tree = {
x: number
y: number
kind: TreeKind
}
const forest: Tree[] = [
{ x: 1, y: 2, kind: getKind("дуб") },
{ x: 3, y: 4, kind: getKind("сосна") },
{ x: 5, y: 6, kind: getKind("дуб") },
{ x: 7, y: 8, kind: getKind("сосна") },
]
console.log("посажено деревьев:", forest.length)
console.log("сохранено видов:", kinds.size)
Когда его использовать
Используйте его, когда профилирование показывает проблемы с памятью из-за множества объектов, повторяющих тяжёлые данные — тайлы карты, глифы, частицы, кэшированные стили.
Не используйте его, если объектов меньше тысяч или общая часть мала. Это паттерн оптимизации: без проблемы с памятью он остаётся просто лишней сложностью.
Плюсы и минусы
Плюсы: большая экономия памяти на больших объёмах; общие данные обновляются в одном месте.
Минусы: с общими объектами нужно обращаться как с доступными только для чтения — одна неосторожная запись изменит «каждый дуб в лесу» (помогает пометить общие поля как readonly); разделение на общую и уникальную части усложняет модель.