زنجیره مسئولیت (Responsibility Chain)
نامهای دیگر: (Chain of Responsibility) CoR، زنجیره فرماندهی
هـــدف
زنجیره مسئولیت یک الگوی طراحی رفتاری است که به شما امکان میدهد درخواستها را در امتداد یک زنجیره از پردازشگرها منتقل کنید. هنگام دریافت یک درخواست، هر پردازشگر تصمیم میگیرد که درخواست را پردازش کند یا آن را به پردازشگر بعدی در زنجیره منتقل کند.
مـسئـــلـه
تصور کنید که در حال کار روی یک سیستم سفارش آنلاین هستید. میخواهید دسترسی به سیستم را محدود کنید تا فقط کاربران تأیید شده بتوانند سفارش ایجاد کنند. همچنین، کاربرانی که مجوزهای اداری دارند باید دسترسی کامل به تمام سفارشها داشته باشند.
پس از کمی برنامهریزی، متوجه شدید که این بررسیها باید به صورت متوالی انجام شوند. برنامه میتواند هر زمان که درخواستی حاوی اعتبارنامه کاربر دریافت کرد، تلاش کند تا کاربر را در سیستم تأیید کند. با این حال، اگر آن اعتبارنامهها صحیح نباشند و تأیید شکست بخورد، دلیلی برای ادامه بررسیهای دیگر وجود ندارد.
در طول چند ماه آینده، چند مورد دیگر از این بررسیهای متوالی را پیادهسازی کردید.
یکی از همکاران شما پیشنهاد کرد که گذراندن دادههای خام مستقیماً به سیستم سفارشدهی خطرناک است. بنابراین، یک مرحله اعتبارسنجی اضافی برای پاکسازی دادهها در یک درخواست اضافه کردید.
بعداً، کسی متوجه شد که سیستم در برابر هک با نیروی بی رحم آسیبپذیر است. برای رفع این مشکل، سریعاً یک بررسی اضافه کردید که درخواستهای تکراری دریافتی از همان آدرس IP را فیلتر میکند.
کسی دیگری پیشنهاد کرد که میتوانید با بازگرداندن نتایج کش شده در درخواستهای تکراری حاوی همان دادهها، سیستم را سرعت بخشید. از این رو، بررسی دیگری اضافه کردید که اجازه میدهد درخواست فقط در صورتی از سیستم عبور کند که پاسخ مناسب کش شده وجود نداشته باشد.
کد بررسیها که قبلاً شبیه یک آشفتگی بود، با افزودن هر ویژگی جدید، بیشتر و بیشتر متورم شد. تغییر یک بررسی گاهی اوقات روی بررسیهای دیگر تأثیر میگذاشت. بدتر از همه، وقتی سعی کردید بررسیها را برای محافظت از سایر اجزای سیستم استفاده مجدد کنید، مجبور بودید برخی از کدها را تکرار کنید زیرا آن اجزا به برخی از بررسیها نیاز داشتند، اما نه همه آنها.
سیستم بسیار دشوار شد و نگهداری آن گران شد. مدتی با کد دست و پنجه نرم کردید تا اینکه یک روز تصمیم گرفتید کل آن را بازسازی کنید.
راهــکــــار
مانند بسیاری از الگوهای طراحی رفتاری، زنجیره مسئولیت به تبدیل رفتارهای خاص به اشیاء مستقل به نام پردازشگرها متکی است. در مورد ما، هر بررسی باید به کلاس جداگانهای با یک متد واحد که بررسی را انجام میدهد، استخراج شود. درخواست، همراه با دادههای آن، به عنوان یک آرگومان به این متد منتقل میشود.
الگو پیشنهاد میکند که این پردازشگرها را به صورت زنجیرهای به هم متصل کنید. هر پردازشگر مرتبط یک فیلد برای ذخیره مرجع به پردازشگر بعدی در زنجیره دارد. علاوه بر پردازش یک درخواست، پردازشگرها درخواست را در امتداد زنجیره منتقل میکنند. درخواست در امتداد زنجیره سفر میکند تا همه پردازشگرها فرصت پردازش آن را داشته باشند.
بهترین قسمت این است که یک پردازشگر میتواند تصمیم بگیرد که درخواست را به پایین زنجیره منتقل نکند و به طور مؤثر هرگونه پردازش بعدی را متوقف کند.
در مثال ما با سیستمهای سفارش، یک پردازشگر پردازش را انجام میدهد و سپس تصمیم میگیرد که آیا درخواست را به پایین زنجیره منتقل کند یا خیر. با فرض اینکه درخواست حاوی دادههای صحیح است، تمام پردازشگرها میتوانند رفتار اصلی خود را اجرا کنند، چه بررسیهای تأیید هویت باشند یا کش کردن.
با این حال، رویکردی کمی متفاوت (و کمی بیشتر متعارف) وجود دارد که در آن، هنگام دریافت یک درخواست، یک پردازشگر تصمیم میگیرد که آیا میتواند آن را پردازش کند یا خیر. اگر بتواند، درخواست را به هیچ جا منتقل نمیکند. بنابراین فقط یک پردازشگر است که درخواست را پردازش میکند یا اصلاً هیچکدام. این رویکرد هنگام برخورد با رویدادها در پشتههای عناصر در یک رابط کاربری گرافیکی بسیار رایج است.
به عنوان مثال، هنگامی که یک کاربر روی یک دکمه کلیک میکند، رویداد از طریق زنجیره عناصر رابط کاربری که با دکمه شروع میشود، در امتداد ظروف آن (مانند فرمها یا پنلها) حرکت میکند و در پنجره اصلی برنامه به پایان میرسد. رویداد توسط اولین عنصر در زنجیره که قادر به رسیدگی به آن است، پردازش میشود. این مثال همچنین قابل توجه است زیرا نشان میدهد که یک زنجیره همیشه میتواند از یک درخت شی استخراج شود.
ضروری است که همه کلاسهای پردازشگر یک رابط مشترک را پیادهسازی کنند. هر پردازشگر مشخص فقط باید به داشتن متد اجرا اهمیت دهد. به این ترتیب میتوانید زنجیرهها را در زمان اجرا با استفاده از پردازشگرهای مختلف ترکیب کنید بدون اینکه کد خود را به کلاسهای مشخص آنها متصل کنید.
ســاخــتـــار