الگوی Chain Of Responsibility

الگوی ChainOfResponsibility(زنجیره ی مسئولیت) در دسته الگوهای رفتاری قرار دارد. اجتناب از اتصال( coupling ) فرستنده درخواست به گیرنده خود، با دادن بیش از یک شی برای فرصت رسیدگی به درخواست. زنجیره ای از اشیای دریافت شده و درخواست در طول زنجیره عبور می کند تا زمانی که یک شی آن را مدیریت کند. به عبارت دیگر شکستن اتصال مستقیم درخواست دهنده به کسی که درخواست را سرویس می‌دهد با ایجاد زنجیره ای از اشیا، سرویس دهنده که یکی پس از دیگری بر حسب اولویت برای پاسخگویی به درخواست ،تلاش کرده و اگر قادر به سرویس‌دهی درخواست نباشد این مسئولیت را به شی بعدی زنجیره ارجاع می‌دهد. UML class diagram شركت كنندگان کلاس ها و اشیاء شرکت کننده در این الگو عبارتند از:مدیریت کننده - رسیدگی کننده Handler (تصویب کننده در مثال دنیای واقعی Approver) : یک واسط را برای رسیدگی به درخواست ها تعریف می کند.(اختیاری) پیوند جانشین ( successor link ) را پیاده سازی می کند.(successor لینکی است که یک handler را به handler بعدی وصل میکند.)توجه:HandleRequest() متدی است که Client از طریق آن درخواستش را اعلام می‌کند.به عبارت دیگر واسطی است که ساختار handler ها را تعریف میکند.مدیریت کننده سفت ConcreteHandler (مدیر، معاون رئیس جمهور، رئیس جمهور Director, VicePresident, President) :مسئولیت رسیدگی به درخواست ها رسیده به خود را دارد.می تواند به جانشینش دسترسی پیدا کند.اگر ConcreteHandler بتواند درخواست را اداره کند، این کار را انجام می دهد؛ در غیر این صورت این درخواست به جانشینش فرستاده می شود. به عبارت دیگر کلاس هایی هستند که واسط handler را پیاده سازی کرده اند.کلاینت Client (اپ زنجیره ChainApp):درخواست را به یک شی ConcreteHandler در زنجیره آغاز می کند. به عبارت دیگر کسی هست که درخواست برای سرویس دهی دارد. توجه: وجود لینک successor از یکhandler به handler بعدی الزامی نیست و انتخاب حمله بعدی می‌تواند به شیوه دیگری انجام شود. ساختار کلی کدکد ساختاری آن الگوی الگوی زنجیره مسئولیت را نشان می دهد که در آن چندین اشیاء مرتبط (زنجیره ای) فرصتی برای پاسخ به یک درخواست ارائه می دهند یا آن را به شی بعدی در خط می دهند. using System; namespace DoFactory.GangOfFour.Chain.Structural { /// <summary> /// MainApp startup class for Structural /// Chain of Responsibility Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main () { // Setup Chain of Responsibility Handler h1 = new ConcreteHandler1 (); Handler h2 = new ConcreteHandler2 (); Handler h3 = new ConcreteHandler3 (); h1.SetSuccessor (h2); h2.SetSuccessor (h3); // Generate and process request int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 }; foreach (int request in requests) { h1.HandleRequest (request); } // Wait for user Console.ReadKey (); } } /// <summary> /// The 'Handler' abstract class /// </summary> abstract class Handler { protected Handler successor; public void SetSuccessor (Handler successor) { this.successor = successor; } public abstract void HandleRequest (int request); } /// <summary> /// The 'ConcreteHandler1' class /// </summary> class ConcreteHandler1 : Handler { public override void HandleRequest (int request) { if (request >= 0 && request < 10) { Console.WriteLine ("{0} handled request {1}", this.GetType ().Name, request); } else if (successor != null) { successor.HandleRequest (request); } } } /// <summary> /// The 'ConcreteHandler2' class /// </summary> class ConcreteHandler2 : Handler { public override void HandleRequest (int request) { if (request >= 10 && request < 20) { Console.WriteLine ("{0} handled request {1}", this.GetType ().Name, request); } else if (successor != null) { successor.HandleRequest (request); } } } /// <summary> /// The 'ConcreteHandler3' class /// </summary> class ConcreteHandler3 : Handler { public override void HandleRequest (int request) { if (request >= 20 && request < 30) { Console.WriteLine ("{0} handled request {1}", this.GetType ().Name, request); } else if (successor != null) { successor.HandleRequest (request); } } } } OutputConcreteHandler1 handled request 2ConcreteHandler1 handled request 5ConcreteHandler2 handled request 14ConcreteHandler3 handled request 22ConcreteHandler2 handled request 18ConcreteHandler1 handled request 3ConcreteHandler3 handled request 27ConcreteHandler3 handled request 20یاabstract class Handler { protected Handler successor; protected int from; protected int to; public Handler(int from, int to, Handler successor) { this.successor = successor; this.from = from; this.to = to; } public virtual void HandleRequest(int request) { if (request >= this.from && request < this.to) { Console.WriteLine("{0} handled request for {1}", this.GetType().Name, request); } else if (successor != null) { successor.HandleRequest(request); } else Console.WriteLine("Request for {0} can not be handled", request); } } class ConcreteHandler1: Handler { public ConcreteHandler1(Handler successor = null): base(1, 10, successor) { } } class ConcreteHandler2: Handler { public ConcreteHandler2(Handler successor = null): base(11, 20, successor) { } } class ConcreteHandler3: Handler { public ConcreteHandler3(Handler successor = null): base(21, 30, successor) { } } class Test { static void Main() { var h1 = new ConcreteHandler1(); var h2 = new ConcreteHandler2(h1); var h3 = new ConcreteHandler3(h2); h3.HandleRequest(8); h3.HandleRequest(12); h3.HandleRequest(3); h3.HandleRequest(24); h3.HandleRequest(19); h3.HandleRequest(33); h3.HandleRequest(17); h3.HandleRequest(1); h3.HandleRequest(15); h3.HandleRequest(28); Console.ReadKey(); } } /* OUTPUT:ConcreteHandler1 handled request for 8ConcreteHandler2 handled request for 12ConcreteHandler1 handled request for 3ConcreteHandler3 handled request for 24ConcreteHandler2 handled request for 19Request for 33 can not be handledConcreteHandler2 handled request for 17ConcreteHandler1 handled request for 1ConcreteHandler2 handled request for 15ConcreteHandler3 handled request for 28*/مثال دنیای واقعیالگوی زنجیره مسئولیت را نشان می دهد که در آن مدیران و مدیران مربوطه می توانند به یک درخواست خرید پاسخ دهند یا آن را به یک مدیر برتر ارسال کنند. هر موقعیت می تواند مجموعه ای از قوانین خود را داشته باشد که سفارشات آنها را تایید می کنند. using System; namespace DoFactory.GangOfFour.Chain.RealWorld { /// <summary> /// MainApp startup class for Real-World /// Chain of Responsibility Design Pattern. /// </summary> class MainApp { /// <summary> /// Entry point into console application. /// </summary> static void Main () { // Setup Chain of Responsibility Approver larry = new Director (); Approver sam = new VicePresident (); Approver tammy = new President (); larry.SetSuccessor (sam); sam.SetSuccessor (tammy); // Generate and process purchase requests Purchase p = new Purchase (2034, 350.00, "Assets"); larry.ProcessRequest (p); p = new Purchase (2035, 32590.10, "Project X"); larry.ProcessRequest (p); p = new Purchase (2036, 122100.00, "Project Y"); larry.ProcessRequest (p); // Wait for user Console.ReadKey (); } } /// <summary> /// The 'Handler' abstract class /// </summary> abstract class Approver { protected Approver successor; public void SetSuccessor (Approver successor) { this.successor = successor; } public abstract void ProcessRequest (Purchase purchase); } /// <summary> /// The 'ConcreteHandler' class /// </summary> class Director : Approver { public override void ProcessRequest (Purchase purchase) { if (purchase.Amount < 10000.0) { Console.WriteLine ("{0} approved request# {1}", this.GetType ().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest (purchase); } } } /// <summary> /// The 'ConcreteHandler' class /// </summary> class VicePresident : Approver { public override void ProcessRequest (Purchase purchase) { if (purchase.Amount < 25000.0) { Console.WriteLine ("{0} approved request# {1}", this.GetType ().Name, purchase.Number); } else if (successor != null) { successor.ProcessRequest (purchase); } } } /// <summary> /// The 'ConcreteHandler' class /// </summary> class President : Approver { public override void ProcessRequest (Purchase purchase) { if (purchase.Amount < 100000.0) { Console.WriteLine ("{0} approved request# {1}", this.GetType ().Name, purchase.Number); } else { Console.WriteLine ( "Request# {0} requires an executive meeting!", purchase.Number); } } } /// <summary> /// Class holding request details /// </summary> class Purchase { private int _number; private double _amount; private string _purpose; // Constructor public Purchase (int number, double amount, string purpose) { this._number = number; this._amount = amount; this._purpose = purpose; } // Gets or sets purchase number public int Number { get { return _number; } set { _number = value; } } // Gets or sets purchase amount public double Amount { get { return _amount; } set { _amount = value; } } // Gets or sets purchase purpose public string Purpose { get { return _purpose; } set { _purpose = value; } } } } OutputDirector Larry approved request# 2034President Tammy approved request# 2035Request# 2036 requires an executive meeting!منبع