Sorumluluk Zinciri Tasarım Kalıbı Chain of Responsibility (CoR)

Sorumluluk Zinciri Tasarım Kalıbı Chain of Responsibility (CoR)

Tasarım kalıpları kütüphanesinin gözden ırak tozlu raflarında unutulmuya yüz tutmuş melankoliği Sorumluluk Zinciri Kalıbı (CoR).

 

Teşbihte hata olmaz, yukarıdaki benzetmeler CoR’ un tasarım kalıpları alemindeki yerini gayet veciz bir şekilde anlatıyor. GOF (Gang of Four) tasarım kalıpları içerisinde yer alan CoR, farklı kullanım alanları ile ilginizi çekmeye aday.

 

Gerçek hayatta karşılaştığımız örnekler bu kalıbı anlatmak için güzel bir zemin oluşturuyor. Düşününki kendinizi bürokratik çarkların döndüğü hiyerarşik bir düzenin içine attınız. Farzi mahal TEDAŞ’ a gittiniz ve yeni bir sözleşme yapmak istiyorsunuz. Önce danışmadan bir beye elektrik kontratı yapmak istiyorum kime başvurmam gerekir diye soruyorsunuz oda sizi sözleşmeler biriminden Fatih beye yönlendiriyor. Merdivenleri çıkarken doğru kişiyi buldum diye düşünürken Fatih beyin masasına geliyorsunuz. Fatih beye “şey ben elektrik hattım için yeni sözleşme yapacaktım size yönlendirdiler yardımcı olabilirmisiniz“ diye soruyorsunuz. Fatih bey de size “ev mi işyeri mi?“ sorusunu yöneltiyor. Sizden işyeri cevabını aldıktan sonra sizi işyeri sözleşmeleri ile ilgilenen Özlem hanıma yönlendiriyor. Sonunda işinizi halledecek merciiye ulaştınız ve sözleşmenizi yaptırdınız.

 

 

Tanım

 

Çok basit manada yukarıdaki örnek ile sorumluluk zinciri tasarım kalıbına gerçek hayattan bir giriş yaptık. Peki bu işin erbabı ne demiş ona bakalım. Hem ingilizcesi hem de kıt kanaat tercümem ile bu tasarım kalıbının tanımı:

 

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

 

Gönderilen istek yada çağrının birden çok işleyici(handler) sınıf üzerinden geçmesine olanak sağlayıp çağıranın alıcı nesneye olan bağımlılığından kaçının. İşleyici (Alıcı) nesnelerden kurulu bir zincir ile gelen istek ve çağrının mutlaka o zincirden geçmesini  ve işlenmesini sağlayın.

 

 

Açık konuşmak gerekirse hayatımın en zor tercümelerinden biriydi. Bu tanımlar örnekler ve bazı açıklamalar olmadan çok havada tabirler.

 

Tasarım kalıpları 2 temel prensip üzerine inşa edilmiştir. bunlar:

 

§       Interface’ ler üzerine programlayın, somut uygulamalar üzerine değil

§       Kalıtım ve sınıf hiyerarşileri yerine nesne kompozisyonlarını kullanın

 

Buradan hareketle ihtiyaçlarımıza cevap verecek kodları yazarken ve nesne tasarımı yaparken mutlaka abstract sınıf ve interfaceler üzerine kodlar yazmalı, uzun nesne hiyerarşilerinden kaçınarak bunun yerine nesne kümeleri ve kompozisyonlarını tercih etmeliyiz. Temelde basit olan bu 2 mantık tüm tasarım kalıplarının DNA’ sında gizlidir.

 

Davranışsal (behavioral) tasarım kalıpları içersinde yer alan CoR; gelen istek ve taleplerin, kapsamı ve kuralları belirlenmiş bir işleyici zincirinden geçmesi ve mutlaka bir işleyici tarafından karşılanmasını sağlar.

 

Zincirin son halkası hariç İşleyici (handler) sınıflar zincirdeki bir sonraki halkanın (successor) referansını kullanırak gelen talebin kendisi tarafından karşılanıp karşılanmayacağına karar verir, eğer bu istek zincirdeki bir üst halkanın sorumluluk alanında ise bu isteği ona yönlendirir. Bu süreç zincirdeki ara bir işleyicinin talebi karşılaması yada son işleyici sınıfa kadar talebin ulaşması ve sonlandırılmasını kapsar. CoR’ un içinde geçen sorumluluk kavramı, zincirde yer alan tüm işleyicilerin ayrı bir sorumluluk alanına sahip olduğunu gösterir. Bu sorumluluk zincirinde yer alan sınıflardan birisi gelen isteklere cevap vermekle yükümlüdür.

 

Örnek

 

Aşağıdaki örnekte tipik bir satınalma talebinin şirket politikasına uygun olarak CoR ile gerçekleştirilmesi işlenmiştir. Sürece ilişkin iş kuralları şunlardan oluşmaktadır:

 

§       Gelen her satın alma talebi bir departmanla ilişkilidir. Her departmanın yıllık bütçe limitleri vardır.

§       Gelen tüm satınalma talepleri departman bütçe limitleri ile karşılaştırılır.

§       5000 YTL altındaki talepler eğer departman bütçe limitleri altında ise şefler tarafından onaylanır.

§       5000 – 10.000 YTL arasındaki bütçe limitini aşmayan satınalma talepleri departman müdürleri tarafından onaylanır.

§       10.000 – 50.000 YTL arasındaki limit dahilindeki talepler finans müdürü tarafından onaylanır.

§       50.000 – 100.000 YTL arasındaki talepler finans bölümünün genel toplantı değerlendirmesine tabidir.

§       100.000 YTL üzerindeki talepleri malesef kabul edemiyoruz, çok üzgünüz!!!

 

Bundan sonrasını merakla beklediğiniz kodlara bırakıyorum.

 

Satınalma Talebi

 

///

   /// Satınalma Emri (Talebi)

   ///

   public class PurchaseOrder

   {

 

      private string _claimer; // Talebi yapan kişi

      private string _deparment; // Talebin yapıldığı

      private string _product; // Talep Edilen ürün yada hizmet

      private decimal _amount; // Satınalma tutarı

      private DateTime _requireDate; // Beklenen satınalma onayı

 

      public string Product

      {

         get { return _product; }

         set { _product = value; }

      }

 

      public decimal Amount

      {

         get { return _amount; }

         set { _amount = value; }

      }

 

      public DateTime RequireDate

      {

         get { return _requireDate; }

         set { _requireDate = value; }

      }

 

      public string Claimer

      {

         get { return _claimer; }

         set { _claimer = value; }

      }

 

      public string Deparment

      {

         get { return _deparment; }

         set { _deparment = value; }

      }

 

   }

 

İşleyici (Handler)

 

   public abstract class ApprovalHandler

   {

      protected ApprovalHandler successor;

 

      public void SetApprovalSuccessor(ApprovalHandler approvalHandler)

      {

         this.successor = approvalHandler;

      }

 

      public abstract void ProcessPurchaseOrder(PurchaseOrder purchaseOrder);

   }

 

Somut (Concrete) Handlerlar

 

   public class ChiefApprovalHandler: ApprovalHandler 

   {

 

      public override void ProcessPurchaseOrder(PurchaseOrder purchaseOrder)

      {

 

         // Satınalma talebi 5000 YTLden küçük ve departman bütçe limitlerini aşmıyorsa üst yöneticisi onaylar

         if (purchaseOrder.Amount < 5000 &&

            Common.CheckDepartmentLimits(purchaseOrder.Amount, purchaseOrder.Deparment))

         {

            Console.WriteLine("Purchased order with the amount {0} is approved by Chief", purchaseOrder.Amount);

 

         }

         else if(this.successor != null)

         {

            Console.WriteLine("Purchase order with the amount {0} is directed to Department Manager.",purchaseOrder.Amount);

            this.successor.ProcessPurchaseOrder(purchaseOrder);

         }

 

      }

 

   }

 

   public class DepartmentManager: ApprovalHandler

   {

      public override void ProcessPurchaseOrder(PurchaseOrder purchaseOrder)

      {

 

         // Satınalma talebi 10000 YTLden küçük ve departman bütçe limitlerini aşmıyorsa üst yöneticisi onaylar

         if (purchaseOrder.Amount < 10000 &&

            Common.CheckDepartmentLimits(purchaseOrder.Amount, purchaseOrder.Deparment))

         {

            Console.WriteLine("Purchased order with the amount {0} is approved by your Department Manager", purchaseOrder.Amount);

 

         }

         else if (this.successor != null)

         {

            Console.WriteLine("Purchase order with the amount {0} is directed to Finance Manager.", purchaseOrder.Amount);

            this.successor.ProcessPurchaseOrder(purchaseOrder);

         }

         else

         {

            throw new Exception("Approval chain error");

         }

 

      }

   }

 

 

   public class FinanceManagerApprovalHandler: ApprovalHandler

   {

 

      public override void ProcessPurchaseOrder(PurchaseOrder purchaseOrder)

      {

         if(Common.CheckDepartmentLimits(purchaseOrder.Amount,purchaseOrder.Deparment))

         {

            Console.WriteLine("Your purchase order with the amount {0} is approved by Finance Manager", purchaseOrder.Amount);

         }

         else if (purchaseOrder.Amount > 50000 && purchaseOrder.Amount < 100000)

         {

            // Onay zincirindeki son halka finans müdürü eğer 50000 YTL" ibn altında ise satınalma talebini daima kontol etmeli ve onaylamalıdır.

            Console.WriteLine("Purchased order with the amount {0} is waiting approval by Finance Manager", purchaseOrder.Amount);

 

            // Finans müdürüne satınalma talebine ilişkin iş emri açılır

            Common.CreateWorkItem("Purchase order approval", "Finance Manager");

         }

         else // Ayağını yorganına göre uzat biraz bekle bu konuyu görüşelim!

         {

            Console.WriteLine("Your purchase order with the amount {0} needs finance commitment!",purchaseOrder.Amount);

         }

      }

 

   }

 

Factory Method Zincir Fabrikası

 

   public static class ApprovalHandlerFactory

   {

      ///

      /// Onay zincirinin yaratılması işini Static Factory Method tasarım kalıbını kullanarak

      /// bu sınıfın üzerine yıkıyoruz, böylece ilgilerin ayrılması, onay zincirinin sırası ve yaratım sürecini

      /// bu sınıf üzerinden gerçekleştiriyoruz.

      ///

      /// Onay zincirini içeren işleyici

      public static ApprovalHandler CreateApprovalHandlerChain()

      {

         // Zincirde bulunan ünvanlar yaratılıyor...

         ChiefApprovalHandler chief = new ChiefApprovalHandler();

         DepartmentManager depManager = new DepartmentManager();

         FinanceManagerApprovalHandler financeManager = new FinanceManagerApprovalHandler();

 

         // Onay zinciri inşa ediliyor

         chief.SetApprovalSuccessor(depManager);

         depManager.SetApprovalSuccessor(financeManager);

 

         // Zincirin ilk halkası olan bölüm şefi alınıyor.

         return chief;

      }

 

   }

 

İstemci (Client)

 

   class Program

   {

      static void Main(string[] args)

      {

        

         ApprovalHandler handler = ApprovalHandlerFactory.CreateApprovalHandlerChain();

 

         PurchaseOrder po = new PurchaseOrder();

 

         po.Amount = 5500;

         po.Claimer = "Oğuz BAYRAM";

         po.Deparment = "IT";

         po.Product = "Server";

         po.RequireDate = DateTime.Now;

 

         handler.ProcessPurchaseOrder(po);

 

         Console.ReadLine();

      }

   }

 

Sonuç

 

Purchase order with the amount 5500 is directed to Department Manager.

Purchased order with the amount 5500 is approved by your Department Manager

 

UML

 

 

Uygulama Alanları

 

§       İş süreçlerinde geçen basit onay zincirleri

§       Dayanıklı ve güvenilir loglama (Exception ve Audit) sistemleri:

§       CoR tasarım kalıbı ile loglama gereksinimlerini mümkün olan en güvenli şekilde CoR kalıbı ile gerçekleştirebilirsiniz. Örneğin oluşan istisnai durumları mutlaka loglamak istiyorsunuz ve bunu yaparken sadece veritabanını kullanmak istemiyorsunuz. Veritabanının cevap veremediği durumlarda da oluşan istisnaların bir şekilde doğru şekilde loglanması temel ihtiyacınız. Bu ihtiyaç için veritabanı, text log dosyaları ve event log gibi log kaynaklarını kullanan işleyicilerden kurulu bir zincir ile oluşan hataları ve ististanaları loglamanız mümkün.

§       HttpHandler’ lar

Döküman Arama

Başlık :

Kapat