Ce este
Șablonul Flyweight economisește memorie atunci când un program ține mii de obiecte similare: partea grea, partajată, este stocată o singură dată și referită de oriunde, în timp ce fiecare obiect păstrează doar mica sa parte unică.
O pădure de 10.000 de arbori nu are nevoie de 10.000 de texturi — are nevoie de 2 specii de arbori și de 10.000 de înregistrări minuscule (x, y, specie).
Exemplu: o pădure cu specii partajate
KindCache::get() distribuie obiecte-specie partajate, creând fiecare dintre ele doar la prima cerere. Fiecare arbore stochează doar o poziție și o referință la specia lui.
Mulți arbori, puține specii
Patru arbori, dar „se creează specia” se afișează doar de două ori — oak și pine există câte o singură dată, indiferent cât de mare devine pădurea. În PHP obiectele se transmit prin referință (handle), așa că fiecare arbore oak indică exact același TreeKind.
Ieșire: script PHP
<?php
// Partea grea, partajată — creată o singură dată pentru fiecare specie.
class TreeKind {
public function __construct(
public string $name,
public string $texture,
) {}
}
class KindCache {
/** @var array<string, TreeKind> */
private static array $kinds = [];
public static function get(string $name): TreeKind {
if (!isset(self::$kinds[$name])) {
echo "se creează specia: ", $name, "\n";
self::$kinds[$name] = new TreeKind($name, $name . ".png");
}
return self::$kinds[$name];
}
public static function count(): int {
return count(self::$kinds);
}
}
// Partea ușoară, proprie fiecărui arbore: o poziție și o referință.
class Tree {
public function __construct(
public int $x,
public int $y,
public TreeKind $kind,
) {}
}
$forest = [
new Tree(1, 2, KindCache::get("oak")),
new Tree(3, 4, KindCache::get("pine")),
new Tree(5, 6, KindCache::get("oak")),
new Tree(7, 8, KindCache::get("pine")),
];
echo "arbori plantați: ", count($forest), "\n";
echo "specii stocate: ", KindCache::count(), "\n";
Când să îl folosești
Folosește-l când profilarea arată probleme de memorie cauzate de multe obiecte care repetă date grele — plăci de hartă, glife, particule, stiluri păstrate în cache.
Renunță la el sub câteva mii de obiecte sau când partea partajată este mică. Acesta este un șablon de optimizare: fără problema de memorie, este doar complexitate.
Avantaje și dezavantaje
Avantaje: economii mari de memorie la scară; datele partajate se actualizează într-un singur loc.
Dezavantaje: obiectele partajate trebuie tratate ca fiind doar pentru citire — o singură scriere neatentă schimbă „fiecare stejar din pădure”; împărțirea în parte partajată și parte unică complică modelul.