C# Chain of Responsibility Pattern Kullanımı - OOP Design Pattern

Chain of Responsibility (Sorumluluk Zinciri) tasarım deseni behavior grubununa ait, bir isteğin belli sınıflar içinde gezdirilerek ilgili sınıfın işlem yapmasını yöneten tasarım desenidir. Chain of responsibility tasarım deseninin dofactory.com a göre kullanım sıklığı 40% lardadır.




Bu deseni anlamaya çalışırken bir çok nesne örneğinin Loosly Coupled (zayıf şekilde) bağlı olduğunu ve bunların bir zincir gibi dizildiğini düşünün. Personel, müdür, genel müdür gibi bir dizilimi buna örnek olarak verelebiliriz. Bir Workflow örneği düşünelim mesela: önce personel işi yapar, sonra müdürü onaylar, sonra genel müdür imza atar. Personel nesnesi işi tamamladıktan sonra işi müdür nesnesine gönderir. Daha sonra müdür nesnesi onaylama işini yapar ve işi genel müdür nesnesine gönderir ve böylece yapılacak iş zincirimizin son halkası olan genel müdür nesnesine gelmiştir ve genel müdür imzalama işini yaparak zinciri sonlandırır. Kısacası zincir içerisindeki nesne örnekleri söz konusu içeriği kendi işlerini yaptıktan sonra bir sonraki adıma gönderirler. Program çalışma mantığına göre istenilen bir yerde zincir sonlandırılabilir veya başa döndürülebilir.


Programlamada Event Based Programming'de sıkça kullanılır. Bir event'ın birden fazla nesne tarafından ele alınması gerektiği durumlarda bu deseni kullanabiliriz. Bu daha çok iç içe bileşenler içeren Form' larda veya diğer taşıyıcı(Container) kontrollerde görebiliriz. Örneğin; tüm formlar için ortak olan bir event tetiklendiğinde, bir zincir şekilde tüm formlar bu event'ı uygulamalıdır. Parent form -> Chield form 1 -> Chield form 2 şeklinde.

Şİmdi örnek olarak basit bir personel izin sistemi yazalım. Engineer -> Program Manager -> HR şeklinde izin onaylama zincirimizin olduğunu düşünerek bir program yazalım:

UML Diagram:


Kod:


    
    /// <summary>
    /// The 'Handler' abstract class
    /// </summary>
    public abstract class Employee
    {
        public Guid EmployeeId { get; set; }
        public int LeaveDays { get; set; }
        // approve edecek bir sonraki kisi
        public Employee NextApprover { get; set; }

        public Employee()
        {
            EmployeeId = Guid.NewGuid();
            LeaveDays = 15;
        }

        // Event tanimlaniyor
        public delegate void OnLeaveApplied(int requestedDays);
        public event OnLeaveApplied onLeaveApplied = null;

        public abstract void ApproveLeave(int requestedDays);

        // Using this we can apply for leave
        public void ApplyLeave(int requestedDays)
        {
            if (onLeaveApplied != null)
            {
                onLeaveApplied(requestedDays);
            }
        }
    }

    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class Engineer:Employee
    {
        public Engineer()
        {
            this.onLeaveApplied += Engineer_onLeaveApplied;
        }

        private void Engineer_onLeaveApplied(int requestedDays)
        {
            if (NextApprover != null)
            {
                NextApprover.ApplyLeave(requestedDays);
            }
        }

        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"Engineer does not have
                       approve permission.");
        }
    }
    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class ProgramManager:Employee
    {
        public ProgramManager()
        {
            this.onLeaveApplied += ProgramManager_onLeaveApplied;
        }

        private void ProgramManager_onLeaveApplied(int requestedDays)
        {
            ApproveLeave(requestedDays);
            if (NextApprover != null)
                NextApprover.ApplyLeave(requestedDays);
        }

        // If we can process lets show the output
        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"EmployeeId: {0} Requested Days: {1} 
                 Approve: {2}",
                this.EmployeeId, requestedDays, "ProgramManager");
        }
    }
    /// <summary>
    /// The 'ConcreteHandler' class
    /// </summary>
    public class HR:Employee
    {
        public HR()
        {
            this.onLeaveApplied += HR_onLeaveApplied;
        }

        private void HR_onLeaveApplied(int requestedDays)
        {
            ApproveLeave(requestedDays);
            if (NextApprover != null)
                NextApprover.ApplyLeave(requestedDays);
        }

        // If we can process lets show the output
        public override void ApproveLeave(int requestedDays)
        {
            Console.WriteLine(@"EmployeeId: {0} Requested Days: {1} 
                 Approve: {2}",
                this.EmployeeId, requestedDays, "HR");
        }
    }

class Program
    {
        static void Main(string[] args)
        {
            Engineer engineer = new Engineer();
            ProgramManager programManager = new ProgramManager();
            HR hr = new HR();

            //workflow u olusturuyoruz
            engineer.NextApprover = programManager;
            programManager.NextApprover = hr;

            engineer.ApplyLeave(3);

            Console.ReadLine();
        }

    }

Çıktı:








0 yorum :

Yorum Gönder