Image
Kasım 22 2015 02:28

Flyweight Design Pattern

           Bellek tüketimini optimize ederek belleği gereksiz işlemlerden arındırmak ve daha verimli kullanmak için tasarlanmış bir tasarım desenidir. Structural Patterns gurubu içerisinde yer alır
Temal mantığı: bir nesneyi onlarca defa create edip bellekte saklamak yerine bir havuz içine “tek bir tane” atıp gerektiğinde o nesneyi “CLR” dokunmadan bu havuzdan çekip kullanmak suretiyle belleği efektif kullanmak işidir diyebiliriz.
Evet tanımı kısa ve öz faydası büyük kullanımı kolaydır.

Tekrar ihtiyacın olacağını düşündüğün bir nesne varsa bu nesneyi memoryde sakla lazım olduğunda memoryden çek kullan. 
Evet evet bildiniz. Cache yapısına çok benziyor. Bir anahtar ile nesneyi saklama işidir bir anlamda. Nesne lazım olduğunda sor bakalım eğer varsa al kullan nesne yoksa bir tane yarat ve sakla sonra al onu kullan.
Dikkat nesne varsa kullan yoksa yarat kullan değil Lazy Load ile karıştırmayın. Nesne varsa kullan yoksa yarat ve sakla sonra kullan.

C# string sınıfını bilmeyen yoktur. Tahmin ettiğiniz gibi string sınıfı içerisinde Flyweight yapar.

Yani :  

string s1 = "Yeşil başlı gövel ördek";
string s2 = new StringBuilder().Append("Yeşil başlı").Append(" gövel ördek").ToString();
string s3 = String.Intern(s2);
Console.WriteLine((Object)s2 == (Object)s1); // Different references.
Console.WriteLine((Object)s3 == (Object)s1); // The same reference.

Bu yüzden string sınıfı sealed bir class türetemezsin dokunamazsın, referans tiplidir value type gibi çalışır. Yoksa her string için gidip memoryden yeni bir string clası türetsek sanırım memory de başka bir şeye yer kalmaz.
 Bu tasarımda bütün flyweight nesneleri tarafından saklanan paylaşılmış alanlara intrinsic, İstemci tarafında saklanan flyweight nesne verilerine ise extrinsic denilmektedir. 

UML diyagramına göz attıktan sonra bir örneğimize geçebilirz.

Blog image

 

Bir zeminimiz var ve biz bu zemini taş yada porselen karolarla kaplamak istiyoruz. Bu yüzden 30x30 ebatlarında Porselen yada taş kareler çizip bunları ekranın rastgele bir noktasında koyacak bir örnek yapacğız.
Ben basit bir örnek olduğu için bir tane Windows Form projesi oluşturdum. Tek formluk bir proje. DomainModels adında bir klasör oluşturup aşağıdaki classları bu klaör altına ekledim.
ITile.cs

 // Karoların türetileceği base sınıfımız 
    public interface ITile
    {
        void Draw(Graphics g, int x, int y);
    }

Factory Pattern tasarım deseni ile hangi koronun create edileceğini belirliyoruz. 

TileFactory.cs 
Tiles adında bir dictionary create ediliyor flyweight yapısı bunun üzerinden işeyecek, Porselen yada Taş karo oluşturulmak istendiğinde bu disctionary-e soruyor bu karo nesnesi varmı sende
varsa alıyor yoksa crate edilip dictionarye atılıyor.

public class TileFactory
    {
        static readonly Dictionary<string, ITile> Tiles = new Dictionary<string, ITile>();

        public static ITile GetTile(string tileType)
        {            
            switch(tileType)
            {
                case "Ceramic":
                    if (!Tiles.ContainsKey("Ceramic"))
                        Tiles["Ceramic"] = new CeramicTile();
                    return Tiles["Ceramic"];                                        
                case "Stone" :
                    if (!Tiles.ContainsKey("Stone"))
                        Tiles["Stone"] = new StoneTile();
                    return Tiles["Stone"];                    
                default:
                    break;
            }
            return null;
        }
    }

 

Karo nesnelerini türeteceğimiz Astaract base clasımız ve hangi karonun create edileceği Factory sınıfımızı yazdıkdan sonra artık Karo sınıflarını yazmaya başlayabiliriz artık.
StoneTile.cs (Taş Karo - mavi renkte olacak )

public class StoneTile : ITile
    {
        public static int ObjectCounter = 0;

        readonly Brush _paintBrush;        
         
        public StoneTile()
        {
            _paintBrush = Brushes.Blue;
             
            ++ObjectCounter;
        }

        public void Draw(Graphics g, int x, int y)
        {
            g.FillRectangle(_paintBrush, x, y, 30, 30);
        }
    }


CeramicTile.cs (Porselen karo - kırmızı renkte olacak)

 public class CeramicTile : ITile
    {
        public static int ObjectCounter = 0;

        readonly Brush _paintBrush;        
 
        public CeramicTile()
        {
            _paintBrush = Brushes.Red;
 
            ++ObjectCounter;
        }

        public void Draw(Graphics g, int x, int y)
        {
            g.FillRectangle(_paintBrush, x, y, 30,30);
        }
    }

Form  

Blog image

Formda bir adet StatusStrip nesnesi eklendi. Formun Kod tarafında ise
TileDemo.cs

 public partial class TileDemo : Form
    {
        readonly Random _random =  new Random();

        public TileDemo()
        {
            InitializeComponent();
        }

        protected override void OnPaint(PaintEventArgs e)
        {            
            base.OnPaint(e);

            for (int i = 0; i < 50; i++)
            {
                ITile ceramicTile = TileFactory.GetTile("Ceramic");
                ceramicTile.Draw(e.Graphics, GetRandomNumber(), 
                    GetRandomNumber());
            }

            for (int i = 0; i < 50; i++)
            {
                ITile stoneTile = TileFactory.GetTile("Stone");
                stoneTile.Draw(e.Graphics, GetRandomNumber(), 
                    GetRandomNumber());
            }

            this.toolStripStatusLabel1.Text = "Total Objects Created : " + 
                Convert.ToString(CeramicTile.ObjectCounter 
                + StoneTile.ObjectCounter);
        }

        private int GetRandomNumber()
        {
            return (int)(_random.Next(350));
        }       
    }


Projei çalıştırdığımızda

Blog image

Görüldüğü biz formda her formdan 50 şer tane oluşturmamıza rağmen aslında sadece iki nesne create edilip memory-e atılıyor ve lazım oldukça kullanılıyor

 

2015 : memet tayanç