msHOWTO

21 Nisan 2012 Cumartesi

C# Design Pattern Chains of Responsibility (CoR)

Merhaba arkadaşlar . Bu makalemde sizlere elimden geldiğince design pattern lerden biri olarn Chains of Responsibility ( sorumluluğun zincirleri ) yani kısaca CoR tasarım modelini anlatmaya çalışacağım arkadaşlar.Aslında türkçe karşılığından da biraz ipucu çıkıyor.Sorumluluğun zincirleri dendiğinde benim aklıma gelen şu ki ortada yapılması gereken bir işlem ve bu işlemin sorumluluğu var ve bu sorumluluğu üstlenen birden fazla nesneler var. İşte aslında temel olarak CoR modeli de bunu sağlar.

Yani uygulandığı yerlerden birisi olan Loglama işlemi üzerinden örnekle açıklamak gerekirse durum şu şekildedir.Şimdi diyelim ki süper bir uygulama yazdınız ve bütün oluşan hataları,yapılan işlemleri kayıt altında tutuyorsunuz.Bu kayıtlarınızı da veri tabanınızda tutuyorsunuz.Süper çalışıyor.Yani kuş uçsa bile kayıt altına alıyor uygulamanız :) Fakat diyelim ki kayıt altına aldığınız yerle bağlantınız koptu ve ya bir şekilde loglama kodlarınızda bir hata oluştu.Eee şimdi ne olacak ? Bütün uçan kuşları kayıt altına alıyordunuz.Veri tabanına bağlantıyı sağlayamadınız.Çat yapılan işlem loglanmadı , oluşan hata loglanmadı... Diyelim ki finansal bir uygulamanız olsun.Bu şekilde sorun oldu. Ve bir kullanıcı binlerce dolarlık işlem yaparken hata oluştu.Sorumlusu kim siz :) Peki bu sorunu nasıl çözeceksiniz.Tabi ki birden fazla loglama şekli oluşturacaksınız.

Normalde bu anlatacağım tasarım modelini bilmiyorsanız bir sürü if ler veya switch case lerle boğuşursunuz.Diyelim ki tüm loglama işlemleri değişti.Hayde en baştan kontrol et de yaz da falan filan... Fakat eğer CoR tasarım modelini biliyorsanız, modelinizi oluşturursunuz ve rahat rahat kullanırsınız.İşte giriş kısmında bahsettiğim sorumluluk loglama işlemine ve zincirler de farklı loglama yollarına karşılık gelmiştir.Faydalarını, çalışma mantığını ve kullanıldığı yerleri anladıysak gelelim anlattığım loglama CoR modelimizi oluşturmaya ...


Not : Uygulamayı console uygulaması olarak yazacağım arkadaşlar.Siz istediğiniz gibi geliştirebilirsiniz.

Öncelikle CoR modelinde bulunacak zincirlerin birbirlerine istek gönderebilecekleri yani aralarında anlaşabilecekleri bir interface yazıyoruz arkadaşlar.


interface ILogger
    {
        ILogger successor { get; set; }
        void Logla(string hata);
    }

ILogger adında bir interface oluşturduk.Ve bu interface in içerisinde zincirlerimizin haberleşeceği successor adında bir property oluşturdum.

Aslında işlemimiz bu kadar . :) Şimdi ise o zincirleri yani nesnelerin classlarını oluşturmaya geldi sıra.Öncelikle database e loglama işlemi yapacak nesnemizi oluşturalım ...

   class DbLoglayici : ILogger
    {
        #region ILogger Members

        public ILogger successor { get; set; }

        public void Logla(string hata)
        {
            int a = 10, b = 0;
            try
            {
                int sonuc = a / b;
                Console.WriteLine("{0} hatası Database'e kaydedildi.", hata);
            }
            catch (Exception)
            {
                if (successor!=null)
                {
                    successor.Logla(hata);
                }
            }
        }

        #endregion
    }

 DbLoglayici adında bir nesnemiz var artık.Ve bu nesnemiz diğer zincirlerle haberleşebilmesi için kendisine ILogger interface ini implemente etmiş durumda.Logla diye bir methodu var dikkat ettiyseniz.Burada try catch blokları arasında loglama işlemini yapan kodlarınızı yazacaksınız.Eğer hata oluşursa diğer zincire geçecek arkadaşlar.Ben yukarıda kendim bir hata oluşturdum.Dolayısıyla bu nesne loglama işlemi yapamayacak ve diğer zincire "Ben yapamadım sorumluluk sende..."Diyecek ve ona gelen hatayı sonraki zincire gönderecek.Aynı mantıkla text dosyasına loglama yapan nesnemizi oluşturalım arkadaşlar...

class TextDosyaLoglayici:ILogger
    {
        #region ILogger Members

        public ILogger successor { get; set; }

        public void Logla(string hata)
        {
            int a = 10, b = 0;
            try
            {
                int sonuc = a / 2;
                Console.WriteLine("{0} hatası Text Dosyaya kaydedildi.",hata );
            }
            catch (Exception)
            {
                if (successor != null)
                {
                    successor.Logla(hata);
                }  
            }
        }

        #endregion
    }

Bu nesnemizde ise try bloğunda bir hata oluşmayacağı için kendinden sonraki zincire herhangi bir sorumluluk iletmeyecek ve işlem tamamlanacak.Şimdi ne olur ne olmaz diye de Event loglama yapan bir nesne oluşturalım arkadaşlar...

class EventLoglayici : ILogger
    {
        #region ILogger Members

        public ILogger successor { get; set; }

        public void Logla(string hata)
        {
            int a = 10, b = 0;
            try
            {
                int sonuc = a / b;
                Console.WriteLine("{0} hatası Event Loglara kaydedildi.", hata);
            }
            catch (Exception)
            {
                Console.WriteLine("Hata Loglanamadı");
            }
        }

        #endregion
    }

Bu nesnemizde de try bloğunda hata oluştu diyelim arkadaşlar.Eee zincir halkasının sonu olduğu için loglama işlemi yapılamaz.Bunu da ekrana yazdırdım ben siz istediğiniz biri işlem yapabilirsiniz.

Evet arkadaşlar zincirlerimizi ve aralarındaki anlaşmayı sağlayan interface i oluşturduktan sonra gelelim bunları kullanmaya ...

            DbLoglayici dbLoglayici = new DbLoglayici();
            TextDosyaLoglayici textDosyaLoglayici = new TextDosyaLoglayici();
            EventLoglayici eventLoglayici = new EventLoglayici();

            dbLoglayici.successor = textDosyaLoglayici;
            textDosyaLoglayici.successor = eventLoglayici;

            dbLoglayici.Logla("Failed by user");
            Console.ReadLine();

Yukarıdaki kodları kullanacağınız yere yazabilirsiniz.Peki bu kodlar ne demek ? Öncelikle loglama işlemlerini yapan nesnelerden birer tane instance alınıyor.Daha sonra bu zincirlerin sırası belirleniyor.Yukarıda ilk önce database e loglama yapan nesne geliyor.Sonrasında ise text dosyaya loglama yapan nesne geliyor.En sonunda ise yani zincirin son halkası olarak event loglama yapan nesne belirleniyor.Ve son olarak ilk zincire yani database loglama yapan zincire hata iletiliyor.

Eğer database loglama yapan zincir hata ile karşılaşırsa sorumluluğu yani işlemi yani burada hatayı kendinden sonra gelen text dosyaya loglama yapan zincire iletiyor.Aynı şekilde text dosyaya loglama yapan zincirde hata olursa event loglama yapan zincire iletiliyor.Fakat en önemli nokta bu kullanımda eğer loglama işlemi başarılı olursa bir sonraki zincire geçilmiyor.Yani işlem nerde başarılı olduysa orada bırakılıyor.

Bu şekilde siz istediğiniz kadar zincir ekleyebilir istediğiniz şekilde bilgiler tutabilir istediğiniz şekilde işlemler gerçekleştirebilirsiniz. 

Umarım faydalı olmuştur arkadaşlar.Bir sonraki makalemde görüşmek dileğiyle...






Hiç yorum yok:

Yorum Gönder