Flyweight Design Pattern

Flyweight Design Pattern

Flyweight pattern, nesne üretiminden kaynaklı bellek kullanımını minimize etmemizi sağlayan bir tasarım kalıbıdır. Eğer bellek tüketimi, çok fazla nesnenin bir arada ele alınmasından kaynaklı ortaya çıkıyorsa burada flyweight tasarım kalıbını kullanabiliriz.

Peki flyweight tasarım kalıbı bu bellek kullanımı minimize etme işlemini nasıl yapıyor? Flyweight tasarım kalıbı havuz mantığıyla çok kullanılan nesnelerin creation işlemini azaltmayı sağlar.

Flyweight tasarım kalıbının yapısına değinecek olursak, bu patternde FlyweightFactory dediğimiz bir classımız vardır. Bu class içerisinde Flyweight classının kalıtımını alan classların yani tekrar tekrar üreteceğimiz classların listesini tutar ve bir metot ile clienta bu listeye erişim verir. Client bu metot üzerinden bir nesne üretmek istediği zaman, metot önce bu nesne elindeki listede yani nesne havuzunda var mı diye bakar. Var ise bu listeden verir. Yok ise de önce bu listeye ekler sonra da eklediğini verir.

Yani kısaca . . .

  • Bir nesne üretmek istediğin zaman FlyweightFactory üzerinden üret.
  • Eğer nesne flyweightFactroy içerisindeki havuzda yer alıyorsa nesneyi sana bu havuzdan döndürecektir. Yok ise önce havuza ekleyip sonra döndürecektir.
  • Havuzdaki nesnelerin common olanları havuzdan alındığı şekilde kullanılır. Spesifikasyon gerekenleri de havuzdan alındıktan sonra customize edilir.

Tabi FlyweightFactory üzerinden alacağımız nesnelerin her zaman her propertylerinin aynı değerde olmasını beklemeyiz. Bazı propertyler ortaktır. Bazıları da ihtiyaca göre set edilir. Burda concreteFlyweight classının sahip olduğu ortak özelliklere intrinsic, farklı olacak olan özelliklere de extrinsic denir. Instrinsic özellikler nesne havuzdan alınırken hazır verilirken extrinsic özellikler client tarafından set edilir.

    enum SoldierType
    {
        Private,
        Sergeant
    }

    // FlyWeight Class
    abstract class Soldier
    {

        #region Intrinsic Fields

        // Bütün FlyWeight nesne örnekleri tarafından ortak olan ve paylaşılan veriler
        protected string UnitName;
        protected string Guns;
        protected string Health;

        #endregion


        #region Extrinsic Fields

        // İstemci tarafından değerlendirilip hesaplanan ve MoveTo operasyonua gönderilerek FlyWeight nesne örnekleri tarafından değerlendirilen veriler
        protected int X;
        protected int Y;

        #endregion


        public abstract void MoveTo(int x, int y);
    }
    // Concrete FlyWeight
    class Private  : Soldier
    {

        public Private()
        {
            // Intrinsict değerler set edilir
            UnitName = "SWAT";
            Guns = "Machine Gun";
            Health = "Good";
        }

        public override void MoveTo(int x, int y)
        {
            // Extrinsic değerler set edilir ve bir işlem gerçekleştirilir
            X = x;
            Y = y;
            Console.WriteLine("Er ({0}:{1}) noktasına hareket etti", X, Y);

        }

    }
    // Concrete FlyWeight
    class Sergeant   : Soldier
    {

        public Sergeant()
        {
            UnitName = "SWAT";
            Guns = "Sword";
            Health = "Good";
        }

        public override void MoveTo(int x, int y)
        {
            X = x;
            Y = y;

            Console.WriteLine("Çavuş ({0}:{1}) noktasına hareket etti",X,Y);
        }

    }
    // FlyWeight Factory
    class SoldierFactory
    {

        // Depolama alanı(Havuz).
        // Uygulama ortamında tekrar edecek olan FlyWeight nesne örnekleri depolama alanında basit birer Key ile ifade edilir
        private Dictionary<SoldierType, Soldier> _soldiers;

        public SoldierFactory()
        {
            _soldiers = new Dictionary<SoldierType, Soldier>();
        }

        public Soldier GetSoldier(SoldierType sType)
        {
            Soldier soldier = null;

            // Eğer depolama alanında, parametre olarak gelen Key ile eşleşen bir FlyWeight nesnesi var ise onu çek
            if (_soldiers.ContainsKey(sType))
                soldier = _soldiers[sType];
            else
            {
                // Yoksa Key tipine bakarak uygun FlyWeight nesne örneğini oluştur ve depolama alanına(havuz) ekle
                if (sType == SoldierType.Private)
                     soldier = new Private();
                if (sType == SoldierType.Sergeant)
                    soldier = new Sergeant();

                _soldiers.Add(sType, soldier);
            }

            // Elde edilen FlyWeight nesnesini geri döndür
            return soldier;

        }

    }
    class Program
    {
        public static void Main()
        {

            // İstemci için örnek bir FlyWeight nesne örneği dizisi oluşturulur
            SoldierType[] soldiers = { SoldierType.Private, SoldierType.Private, SoldierType.Sergeant, SoldierType.Private, SoldierType.Sergeant };


            // FlyWeight Factory nesnesi örneklernir
            SoldierFactory factory = new SoldierFactory();

            // Extrinsic değerler set edilir
            int localtionX = 10;
            int locationY = 10;

            foreach (SoldierType soldier in soldiers)
            {                
                localtionX += 10;
                locationY += 5;

                // O anki Soldier tipi için MoveTo operasyonu çağırılmadan önce fabrika nesnesinden tedarik edilir
                Soldier sld = factory.GetSoldier(soldier);

                // FlyWeight nesnesi üzerinden talep edilen operasyon çağrısı gerçekleştirilir
                sld.MoveTo(localtionX, locationY);

            }

        }

    }