Structural — Yapısal Desenler

Flyweight

Sinek Siklet (Hafif Nesne) Deseni

Amaç: Çok sayıda benzer nesnede tekrar eden ortak veriyi paylaşarak bellek kullanımını azaltmak.

1

Basit Anlatım

Teknik terim yok — günlük hayattan bir benzetme

Bir parkta binlerce ağaç olduğunu düşünün ve bunların hepsini bir resimde çizeceksiniz. Ağaçların çoğu birkaç türden biri: çam, meşe, çınar.

Her ağaç için ayrı ayrı yaprak şekli, dal yapısı, renk paleti tasarlamak saçma olurdu. Bunun yerine her tür için bir kalıp hazırlarsınız. Sonra her ağaç için yalnızca "hangi kalıp, nerede, ne büyüklükte" bilgisini not edersiniz.

Matbaa harfleri

Eski matbaalarda bir kitabı basmak için her harften kalıp kullanılırdı. Kitapta binlerce "a" harfi geçse de "a" kalıbının şekli hep aynıdır. Değişen tek şey harfin sayfadaki konumudur.

Flyweight şunu der: "Herkesin aynı olan kısmını bir kez sakla ve paylaştır; sadece kişiye özel kısmı ayrı tut."
2

Teknik Anlamı

Bir yazılımcının bakış açısıyla

Flyweight, bir nesnenin durumunu ikiye ayırır ve paylaşılabilir kısmı tek bir örnekte toplar:

Katılımcılar

.NET'ten tanıdık örnekler

Ne zaman kullanılır?

Dezavantajlar

3

C# ile Uygulama

Adım adım, çalışan kod örneği

Senaryo: Bir oyun haritasına 100.000 ağaç yerleştiriyoruz. Yalnızca 3 ağaç türü var ve her türün dokusu (texture) büyük bir veri.

Adım 1 Flyweight: paylaşılan ağaç türü (intrinsic durum)

Doku verisi büyük olduğu için her ağaçta tekrar saklanmamalı.

public sealed class TreeType
{
    public string Name { get; }
    public string Color { get; }
    public byte[] Texture { get; }   // büyük veri: ~50 KB

    public TreeType(string name, string color)
    {
        Name = name;
        Color = color;
        Texture = new byte[50_000];
    }

    public void Draw(int x, int y) =>
        Console.WriteLine($"  {Name} ({Color}) çizildi -> konum ({x}, {y})");
}

Adım 2 Flyweight Factory: önbellek

public static class TreeTypeFactory
{
    private static readonly Dictionary<string, TreeType> _cache = new();

    public static TreeType Get(string name, string color)
    {
        string key = $"{name}_{color}";
        if (!_cache.TryGetValue(key, out var type))
        {
            type = new TreeType(name, color);
            _cache[key] = type;
            Console.WriteLine($"  >> Yeni TreeType oluşturuldu: {name}");
        }
        return type;
    }

    public static int CachedCount => _cache.Count;
}

Adım 3 Context: her ağaca özel veri (extrinsic durum)

Her ağaç sadece konumunu ve paylaşılan türe bir referansı tutar.

public class Tree
{
    public int X { get; }
    public int Y { get; }
    public TreeType Type { get; }

    public Tree(int x, int y, TreeType type) { X = x; Y = y; Type = type; }

    public void Draw() => Type.Draw(X, Y);
}

Adım 4 Kullanım

Tüm parçaları bir araya getiren istemci (client) kodu:

string[] names = { "Çam", "Meşe", "Çınar" };
string[] colors = { "koyu yeşil", "yeşil", "açık yeşil" };
var forest = new List<Tree>();
var rnd = new Random(42);

for (int i = 0; i < 100_000; i++)
{
    int t = rnd.Next(3);
    TreeType type = TreeTypeFactory.Get(names[t], colors[t]);
    forest.Add(new Tree(rnd.Next(1000), rnd.Next(1000), type));
}

Console.WriteLine("İlk 3 ağaç:");
forest.Take(3).ToList().ForEach(tree => tree.Draw());

long withFlyweight = TreeTypeFactory.CachedCount * 50_000L;
long withoutFlyweight = forest.Count * 50_000L;
Console.WriteLine($"Ağaç sayısı          : {forest.Count:N0}");
Console.WriteLine($"TreeType nesne sayısı: {TreeTypeFactory.CachedCount}");
Console.WriteLine($"Doku belleği (Flyweight ile)  : {withFlyweight / 1024:N0} KB");
Console.WriteLine($"Doku belleği (Flyweight yoksa): {withoutFlyweight / 1024 / 1024:N0} MB");

Konsol çıktısı

  >> Yeni TreeType oluşturuldu: Çınar
  >> Yeni TreeType oluşturuldu: Meşe
  >> Yeni TreeType oluşturuldu: Çam
İlk 3 ağaç:
  Çınar (açık yeşil) çizildi -> konum (140, 125)
  Meşe (yeşil) çizildi -> konum (168, 262)
  Çınar (açık yeşil) çizildi -> konum (512, 173)
Ağaç sayısı          : 100.000
TreeType nesne sayısı: 3
Doku belleği (Flyweight ile)  : 146 KB
Doku belleği (Flyweight yoksa): 4.768 MB

Kodda dikkat edilmesi gerekenler

Özetle: Flyweight, çok sayıdaki nesnenin ortak kısmını tek örnekte paylaştırarak bellek kullanımını dramatik şekilde azaltır.
← Ana sayfaya dön