Flyweight Pattern – optimizarea memoriei prin reutilizarea obiectelor
Când dezvolți aplicații care procesează un număr foarte mare de obiecte – liste lungi, noduri grafice, caractere, structuri repetitive – consumul de memorie poate deveni rapid o problemă.
Aici intervine Flyweight Pattern, un Structural Design Pattern care permite partajarea obiectelor comune, reducând masiv memoria alocată.
🔍 Ce este Flyweight Pattern?
Flyweight este un pattern care separă starea intrinsecă (care poate fi partajată) de starea extrinsecă (specifică fiecărui obiect).
Astfel, în loc să creezi mii sau milioane de obiecte identice, reutilizezi instanțele deja create.
Este util mai ales în aplicații cu:
-
multe elemente grafice repetate
-
liste mari de date
-
texte caractere-cu-caractere
-
scenarii de cache
-
generare de documente sau hărți
🧠 Conceptul pe scurt
Obiectele se împart în:
-
Stare intrinsecă – proprietăți comune tuturor instanțelor
-
Stare extrinsecă – valori specifice fiecărei utilizări
Chestia cheie: numai starea extrinsecă se pasează la runtime, iar obiectele intrinseci sunt reutilizate.
🏗 Structura actorilor
-
Flyweight – interfața pe care o folosesc toate obiectele partajate
-
ConcreteFlyweight – obiect reutilizabil, ce conține starea intrinsecă
-
FlyweightFactory – creează și gestionează instanțele comune
-
Client – furnizează starea extrinsecă și folosește flyweight-ul
🧪 Exemplu practic în C#
Scenariu: gestionăm caracterele unui text într-un editor. Literele sunt identice ca formă, diferă doar pozițiile lor pe ecran.
🎯 1. Interfața Flyweight
public interface ICharacterFlyweight
{
void Render(int fontSize, int x, int y);
}
🎯 2. Flyweight concret (stare intrinsecă)
public class CharacterFlyweight : ICharacterFlyweight
{
private readonly char _symbol; // intrinsec
public CharacterFlyweight(char symbol)
{
_symbol = symbol;
}
public void Render(int fontSize, int x, int y)
{
Console.WriteLine($"Rendering '{_symbol}' at ({x},{y}) with size {fontSize}");
}
}
🎯 3. Flyweight Factory (cache-ul de caractere)
public class CharacterFlyweightFactory
{
private readonly Dictionary<char, ICharacterFlyweight> _characters = new();
public ICharacterFlyweight GetFlyweight(char symbol)
{
if (!_characters.ContainsKey(symbol))
{
_characters[symbol] = new CharacterFlyweight(symbol);
Console.WriteLine($"Creating new flyweight for '{symbol}'");
}
return _characters[symbol];
}
}
🎯 4. Utilizare Flyweight în aplicație
var factory = new CharacterFlyweightFactory();
string text = "AAABBC";
int x = 0;
foreach (char c in text)
{
var character = factory.GetFlyweight(c);
character.Render(fontSize: 12, x: x, y: 10);
x += 10;
}
📉 Beneficii
✔ Consum redus de memorie
✔ Scalabilitate mare în structuri repetitive
✔ Creștere de performanță în scenarii grafice, hărți, cache
⚠ Dezavantaje
❌ Necesită separarea atentă a stării intrinseci/extrinseci
❌ Crește complexitatea codului
❌ Poate fi supra-inginerie dacă numărul de obiecte nu este mare
🧭 Când să folosești Flyweight?
Folosește-l când:
-
ai foarte multe obiecte similare
-
memoria consumată devine o problemă
-
obiectele împart o mare parte din comportament/stare
-
vrei un cache de obiecte reutilizabile
Evită-l dacă:
-
obiectele sunt puține
-
starea extrinsecă este complicată
-
diferențele între instanțe sunt mari
🔚 Concluzie
Flyweight Pattern este esențial pentru optimizarea memoriei în aplicații mari, repetititve sau grafice. Prin separarea stărilor și reutilizarea obiectelor comune, poți reduce dramatic amprenta RAM, păstrând același comportament funcțional.
Dacă aplicația ta .NET procesează milioane de elemente, acest pattern poate face diferența între un sistem lent și unul performant.