Sinek Siklet Kalıp (Flyweight Pattern)

Eyl 08, 2013
Sinek sıklet kalıp (Flyweight Pattern) nesne temelli yazılım mimarilerinde belirlenmiş temel tasarım kalıplarından biridir. Bu kalıbın amacı yapıca aynı nesneleri bellekte çokça oluşturmak yerine her bir nesnenin bir kopyasını oluşturmak ve oluşturulan nesneleri ortak bir noktada tutup paylaştırma işlemini yerine getirmektir. Yani tekrar eden aynı nesneleri gruplayarak hafızada çok fazla yer kaplamaması için ,hafıza kullanımını minumuma indirmektir. Mesela bir metin dosyası sıkıştırma olayı buna bir örnektir. Aynı metinlerin referansları tutularak yerden kazanç sağlanır.

Tasarım Şablonunun Gerçeklenmesi

Her bir Flyweight nesnesi temel olarak iki veri kümesinden oluşur. Dahili (intrinsic) olarak geçen durum-bağımsız (state-independent) kısım parçalardan birisir. Bu kısımda, çalışma zamanındaki tüm Flyweight nesneleri tarafından saklanan paylaşılmış alanlar yer almaktadır. Diğer parça ise durum-bağımlı (state-dependent) olarak bilinen ve dışsal (extrinsic) olarak belirtilen kısımdır. Bu kümedeki veriler ise istemci tarafından saklanır, hesap edilir ve Flyweight nesne örneğine, yine Flyweight'in bir operasyonu yardımıyla aktarılırlar.

Sinek sıklet tasarım kalıbının UML diyagramı aşağıdaki şekildedir;



Bu sınıf ve/veya nesneler şu şekilde çalışır:

  • FlyWeight: Nesnenin ortak özelliklerini tutan arabirim (interface) veya soyut (abstract) sınıf (class)tır.

  • ConcreteFlyWeight: Flyweight şablonunu uygulayan farklı nesneleri içeren sınıflardır.

  • FlyWeightFactory: Nesneleri ortak bir noktada tutan ve paylaşımını sağlayan sınıftır.

  • Client: İstemci uygulamadır.

Sinek Sıklet Kalıbı İle İlgili Uygulama

Hazırlanan örnek uygulamada her bir harfi temsilen ConcreteFlyweight yapıları oluşturulmuş ve bu yapılar Flyweight abstract class'ını uygulamış ve bu sayede ortak nesne yapısı sağlamışlardır. FlyweightFactory yapısı Flyweight arayüzünü uygulayan nesneleri tutan ve paylaştıran bir yapıda çalışmaktadır. Eğer nesne daha önce üretildiyse üretilen nesneyi, eğer üretilmedi ise yeni ürettiği nesneyi dönmektedir. Örnekte her bir karakterin pointSize değeri farklıdır. Ya da konumları farklı olabilir.

Bu yapıların anlaşılması için gerçekleştirilen C# uygulaması aşağıda görülmektedir.

namespace FlyWeight
{
    class Uygulama
    {
        static void Main()
        {
            string document = "AABBCBCC";
            char[] chars = document.ToCharArray();
  
            CharacterFactory factory = new CharacterFactory();

            // extrinsic state
            int pointSize = 10;

            // For each character use a flyweight object
            foreach (char c in chars)
            {
                pointSize++;
                Character character = factory.GetCharacter(c);
                character.Display(pointSize);
             } 

            Console.ReadKey();
        }
    }
    

    //FlyweightFactory class
    class CharacterFactory
    {
        private Dictionary<char, Character> _characters =
                new Dictionary<char, Character>();

        public Character GetCharacter(char key)
        {
            Character character = null;

            if (_characters.ContainsKey(key))

                character = _characters[key];

            else
            {
                switch (key)
                {
                    case 'A': character = new CharacterA(); break;
                    case 'B': character = new CharacterB(); break;
                    case 'C': character = new CharacterC(); break;
                 }

                 _characters.Add(key, character);
             }

             return character;
        }
    }

    //Flyweight
    abstract class Character
    {
        protected char symbol;
        protected int width;
        protected int height;
        protected int ascent;
        protected int descent;
        protected int pointSize;

        public abstract void Display(int pointSize);
     }

    //ConcreteFlyweight
    class CharacterA : Character
    {
        //Constructor
        public CharacterA()
        {
            this.symbol = 'A';
            this.height = 100;
            this.width = 120;
            this.ascent = 70;
            this.descent = 0;
         }

        public override void Display(int poin
        {
            this.pointSize = pointSize;
            Console.WriteLine(this.symbol +
                              " (pointsize " + this.pointSize + ")");
         }
    }

    class CharacterB : Character
    {
        public CharacterB()
        {
            this.symbol = 'B';
            this.height = 100;
            this.width = 140;
            this.ascent = 72;
            this.descent = 0;
         }

        public override void Display(int pointSize)
        {
            this.pointSize = pointSize;
            Console.WriteLine(this.symbol +
                              " (pointsize " + this.pointSize + ")");
         }
    }

    class CharacterC : Character
    {
        public CharacterC()
        {
            this.symbol = 'C';
            this.height = 100;
            this.width = 100;
            this.ascent = 68;
            this.descent = 0;
         }

        public override void Display(int pointSize)
        {
            this.pointSize = pointSize;
            Console.WriteLine(this.symbol +
                              " (pointsize " + this.pointSize + ")");
        }
    }

}

Bu uygulamanın ekran çıktısı aşağıdaki gibidir.

A <pointsize 11>
A <pointsize 12>
B <pointsize 13>
B <pointsize 14>
C <pointsize 15>
B <pointsize 16>
C <pointsize 17>
C <pointsize 18>