حوزه: Object
هدف: Behavioral
نقش الگو
این الگو یک راه حل برای حالتی است که، در آن درخواستهایی از کاربر به برنامه میرسد و باید با توجه به شرایطی به این درخواستها پاسخ داده شود و در موارد زیر کاربرد دارد.
حال که با موارد استفادهی Chain of Responsibility آشنا شدیم، به طرز کار و پیاده سازی آن میپردازیم، الگوی Chain of Responsibility با لیستی از اشیای handler کار میکند که محدودیتهایی برای پاسخ گویی به درخواستهای کاربر یا کاربران بر اساس نوع درخواستها بر آنها اعمال شده است، اگر یک handler نتواند به یک درخواست پاسخ دهد درخواست را برای handler بعدی در این لیست (زنجیره) میفرستد و به همین ترتیب برنامه کار خواهد کرد و در انتهای زنجیره میتوان یک حالت استثنا یا یک پیشفرض قرار داد تا در صورتی که هیچکدام از handlerها به درخواست پاسخ ندادند آن حالت پیشفرض اتفاق بیافتد و یا به کاربر خطایی نمایش داده شود.
Chain of Responsibility در زندگی روزمرهی ما به وضوح اتفاق میافتد و در هر شرکتی میتوان این الگو را دید، در یک بانک، بیمارستان و ... این الگو وجود دارد، برای مثال در یک بانک، کارمندهای معمولی بانک به بسیاری از درخواست ها پاسخ میدهند، اما درخواستهای خاص مانند وامها به سطح بالاتر برای رسیدگی ارجاع داده میشوند و حتی برای وامهای کلان و برخی دیگر درخواستهای خاص، مدیر بانک باید به درخواست رسیدگی کند و این درخواستها از محدودهی پاسخگویی کارمندان در سطوح پایینتر خارج است. بنابراین حلقهای از عناصر پاسخگو در بانک وجود دارد که بر اساس ماهیت درخواستهای مشتریان عناصر مختلفی پاسخگویی به درخواستها را به عهده میگیرند. همچنین مشاهده میشود که در یک سطح ممکن است چند نفر برای پاسخگویی وجود داشته باشند که همه آنها از امکانات و محدودیتهای مشابه برخوردارند، در حالی که یک بانک تنها یک رئیس دارد اما چندین باجهی پاسخگویی به درخواستهای سطح پایین (که فراوانیه آنها هم از درخواستهای دیگر بیشتر است) وجود دارد و قرار دادن تنها یک باجه سبب تشکیل شدن صفی از مشتریان میشود که باعث خسته شدن مشتریان میگردد و کارایی بانک را بسیار پایین میاورد.
طراحی
نحوهی عملکرد Chain of Responsibility به این صورت است که درخواستی از کاربر مطرح میشود، سپس این الگو درخواست کاربر را در طول زنجیرهی handlerها میگرداند تا handler مناسب برای پاسخگویی به درخواست کاربر پیدا شود. برای آنکه یک handler در زنجیره بتواند به یک درخواست پاسخ دهد باید منابع، دانش و مجوزهای لازم را داشته باشد. Handlerها در سطح خود بر اساس موارد فوق تصمیم میگیرند که میتوانند به یک درخواست پاسخ دهند یا باید درخواست را به عنصر بعدی (یا عنصر در سطح بالاتر) بفرستند.
Chain of Responsibility الگویی ساده است، یک Interface کلی دارد که توسط چندین handler (به تعداد مورد نیاز، یا به تعدادی که میتوانیم ایجاد کنیم) پیاده سازی میشود. هر handler یک لینک به حلقهی بعدی در زنجیره دارد که با توجه به زبانی که مورد استفادهی برنامه نویس قرار میگیرد این لینک ایجاد میگردد تا در صورت لزوم handler درخواست کاربر را به handler بعدی بفرستد. در UML زیر پیاده سازیه Chain of Responsibility بطور ساده نمایش داده شده است.

در این دیاگرام IHandler، interface ای است که handlerها از روی آن را پیاده سازی میشوند، Handler1 و Handler2 دو شی از IHandler Interface هستند که handlerهای تعریف شده برای پاسخ گویی به درخواستهای کاربران میباشند و Successor، Link به شی handler بعدی در زنجیره است. کلاس Client کلاسی است که درخواستها (Requestها) را ایجاد میکند و Request درخواست مطرح شده از سوی کلاس Client است.
و اگر بخواهیم این شکل را با مثال بانک مطابقت دهیم خواهیم داشت:
مشتری = Client
رئیس و کارمندان بانک = Hadlers (Handler1,Handler2)
ارجاع به مسئول بالا رتبه = Successor
درخواست مشتری = Request
چند نکته در طراحی:
پیاده سازی
یک مثال ساده به زبان جاوا به شرح زیر را برای نمونه پیاده سازی میکنیم:
فرض کنید برنامهای شامل پنج Handler است که هر سطح تنها یک handler دارد (یعنی دو handler هم سطح نداریم). هر handler به درخواستهایی تا سقف 1000 برابر ID خود میتواند پاسخ دهد. هر handler به handler در سطح بالاتر link دارد و handlerها از سطح بالا به پایین ایجاد میشوند.
public interface Handler {
public String HandleRequest(int data);
}
public class HandlerA implements Handler {
private Handler next;
private int id;
private int limit;
public HandlerA(int id, Handler handler) {
this.id = id;
limit = id * 1000;
next = handler;
}private int getId() {
return id;
}public int getLimit() {
return limit;
}public void setLimit(int limit) {
this.limit = limit;
}public String HandleRequest(int data) {
if (data < limit) {
return "Request for " + data + " handled at level " + getId();
} else if (next != null) {
return next.HandleRequest(data);
} else {
return ("Request for " + data + " handled BY DEFAULT at level " + getId());
}
}
}
public class App {خروجی
public static void main(String[] args) {
Handler start = null;
for (int i = 5; i > 0; i--) {
System.out.println("Handler " + i + " deals up to a limit of " + i * 1000);
start = new HandlerA(i, start);
}
int[] a = {50, 2000, 1500, 10000, 175, 500};
for (int i : a) {
System.out.println(start.HandleRequest(i));
}
}
}
Handler 5 deals up to a limit of 5000
Handler 4 deals up to a limit of 4000
Handler 3 deals up to a limit of 3000
Handler 2 deals up to a limit of 2000
Handler 1 deals up to a limit of 1000
Request for 50 handled at level 1
Request for 2000 handled at level 3
Request for 1500 handled at level 2
Request for 10000 handled BY DEFAULT at level 5
Request for 175 handled at level 1
Request for 500 handled at level 1
مثال پیاده سازی شده با زبان جاوا را میتوانید از github من دانلود کنید.
برچسب:
نویسنده: سجاد شمس