الگوی طراحیMediator
الگوی Mediator یکی از الگوی طراحی های رفتاری (Behavioral) می باشد. استفاده از این الگوی طراحی باعث یکپارچگی و کاهش بی نظمی در وابستگی (dependency) بین اشیا می شود. در این الگو هر گونه ارتباط مستقیم بین دو شیء را محدود کرده و برای ارتباط پیدا کردن با هم آن ها را مجبور به استفاده از یک شیء رابط به نام Mediator می کنیم.
2.1 طرح مشکل و راه حل
فرض می کنیم که در طراحی صفحات یک وبسایت یا اپلیکیشن، مثل شکل 2-1 به یک یا چند فرم یا Dialog برای دریافت اطلاعات از کاربران نیاز داریم. این فرم ها دارای اجزای مختلفی می باشند از جمله متن، عکس، ایمیل، چک باکس و غیره. بعضی از اجزای یک فرم می توانند عملکردهایی نیز داشته باشند؛ مثلا برای ثبت نام کاربر در وبسایت یک گزینه داشته باشیم تحت عنوان « کد معرف » که با یک check box تعریف شده است و با فعال کردن آن بخش ورودی جدیدی نمایان شود که کاربر داخل آن بتواند یک عدد وارد کند. (و برای معرف مشخص شده نیز پاداشی لحاظ شود.)
برای مثالی یک دکمه در کنار دکمه ثبت قرار دهیم که پیش از ذخیره سازی و ارسال، اطلاعات ورودی را اعتبار سنجی کند. حال آنکه check box گفته شده یا دکمه اعتبار سنجی مکرر در کد ما استفاده شوند.
بنابراین همانطور که در شکل 2-1 نیز ترسیم شده است برخی از اجزای فرم یا Dialog ممکن است با یکدیگر ارتباط داشته باشند و با پیشرفت اپلیکیشن و افزایش روابط، همانطور که در شکل 2-1 evolved نیز ترسیم شده این روابط سبب شلوغ شدن و سخت شدن توسعه کد خواهند شد.
این دقیقا زمانی است که استفاده از الگوی Mediator به ما کمک خواهد کرد. به منظور جلوگیری از تکرار و تمیز تر شدن کد نیاز داریم تا یک واسطه ایجاد کنیم و هر زمان که نیاز به این عملگرها داشته باشیم با صدا کردن یک شیء که این اجزا را در خود جا داده است به سادگی از هر کدام آنها استفاده کنیم. با ایجاد یک کلاس Mediator یا واسطه به جای این که اجزا مختلف در یک فرم به صورت مستقیم با هم ارتباط داشته باشند، به سادگیMediator را صدا می کنند و عملگر مورد نظر را از آن استخراج می کنند. اگر وبسایت مورد نظر وبسایت پر استفاده و محبوبی باشد این کار می تواند به سرعت پردازش داده ها در سرور کمک کند و بار زیادی را از دوش سرور کم کند.
در این کلاس روابطی که نیاز است در فرم ها استفاده شود را از قبل معرفی می کنیم و در فرم ها از آن ها استفاده می کنیم. در شکل 2-2 تغییراتی که با اضافه شدن Mediator در Dialogها ایجاد می شود نمایش داده شده است.
به این صورت همانطور که در شکل 2-2 ترسیم شده است، الگوی Mediator به ما این توانایی را می دهد که یک شبکه ی منظمی از ارتباط بین اجزای مختلف فرم ها ایجاد کنیم و شلختگی یا پیچیدگی را تا حد قابل ملاحظه ای کاهش دهیم.
2.2 ساختار اصلی
همانطور که در شکل 2-3 مشاهده می شود یک فرایند استفاده از الگو Mediator قرار گرفته است. عملکرد این الگو به این صورت می باشد که یک یا چند کلاس میانی ConcreteMediator از یک رابط کاربری اصلی implement می شوند تا ارتباط بین اجزای تعریف شده در داخل خود را مدیریت کنند. در کنار اینکه ممکن است با توجه به شرایط و اجزای مورد نظر نیاز به چند کلاس داشته باشیم ولی در ساختاری که ما به بررسی آن می پردازیم تنها با یک کلاس ConcreteMediator سر و کار خواهیم داشت. در این ساختار 4 بخش وجود دارد که در ادامه به آن ها پرداخته ایم.
اجزا یا کامپوننت های مختلف A,B,C,D کلاس های متنوعی هستند که بخش منطقی برنامه را در خود جای داده اند. این منطق ها، هر تابعی می توانند باشند ولی در اینجا منظور از این منطق ها که در شکل 3-2 با عنوان operation نشان داده شده، یک دستور است که یک عملکرد یا واکنش نسبت به درخواست کاربر را برای ما اجرا کند. هر یک از این اجزا با یک کلاس Mediator در ارتباط می باشند. اجزا در خصوص کلاس اصلی ConcreteMediator اطلاعی ندارند بنابراین در صورت نیاز می توانند به کلاس های ConcreteMediator دیگری نیز اختصاص داده شوند ( برای مثال از همه این کامپوننت ها در یک کلاس ConcreteMediator دیگر به همین شکل استفاده شود ولی واکنش های به درخواست کاربر در کلاس جدید متفاوت باشد).- ارتباط بین اجزا را رابط کاربری Mediatorبا مشخص کردن متدهای ارتباطی تعریف می کند. معمولا یکی از این متدها یک روش ارتباطی به منظور تهیه و ارسال notification بوده که اجزای مورد نظر می توانند با رعایت اینکه هیچ coupling (در هم تنیده شدن چند جزء که به یک دیگر وابسته می شوند و قابلیت استفاده مجدد هر یک از جزء ها در صورت نیاز به تکرار را از بین می برند) بین کلاس ارسال کننده و دریافت کننده ی notification پیش نیاید، هر گونه متن یا محتوایی را ارسال نمایند.
- Concrete Mediatorوظیفه ی چسباندن ارتباط ها بین اجزای گوناگون را دارد و از رابط کاربری Mediator پیاده سازی یا implement شده است. concrete ها یا پایه ریزهای Mediator معمولا منابع همه ی اجزایی که تحت مدیریت خودشان دارند (در اینجا همه ی اطلاعات موجود در کامپوننت های ABCD اعم از متغییر ها یا operation های آن ها) را نگاه می دارند و حتی می توانند چرخه ی استفاده و مدت زمان استفاده از آنها را مدیریت کنند. کلاس ConcreteMediatorپس از دریافت یک ورودی (که می تواند درخواست کاربر باشد) واکنشی که نیاز است نسبت به ورودی نشان داده شود را مشخص می کند و در پاسخ آن را انجام می دهد.
- از آنجایی که هدف ما این است که کامپوننت های ABCD نباید از وجود اجزای دیگر اطلاع داشته باشند ارتباط آن ها را محدود به یک ارتباط مستقیم با رابط کاربری Mediator و کلاس ConcreteMediator می کنیم.
2.3مراحل پیاده سازی
در ابتدا با تعریف کامپوننت های مورد نیاز، operation های مربوطه را در کامپوننت می نویسیم و در کنار آن رابط کاربری Mediator و کلاس اصلی ما که ConcreteMediator نام دارد را پیاده سازی می کنیم و همه ی کامپوننت ها را در این کلاس تعریف می کنیم سپس همانطور که در توضیحات بالا گفته شد برای واکنش های مربوط به هرگونه ارتباط توابع مورد نیاز را تحت عنوان reactOn برای هر کامپوننت تعریف می کنیم. در شکل 2-3 پیش از هر چیز یک متد داریم که notify(Sender) نامگذاری شده است و با یک حلقه ifبررسی می کند که فرستنده در درخواستش به کدام کامپوننت نیاز دارد. با مشخص شدن کامپوننت، کلاس ConcreteMediator نوع واکنشی که برای هر کامپوننت تعریف کرده ایم را صدا زده و آن را اجرا می کند، بدین ترتیب بدون آنکه کامپوننت مورد نظر هیچ اطلاعی داشته باشد، مورد استفاده قرار گرفته است.
از دید هر یک از اجزا این فرایند یک صفحه خالی است و ارسال کننده اطلاعی ندارد که محصول ارسالی آن به کجا فرستاده می شود و چه استفاده ای از آن خواهد شد؛ همچنین دریافت کننده نیز هیچ اطلاعی از واحد ارسال کننده ندارد.
یکی از علت هایی که در اینجا از رابط کاربری یا abstractاستفاده می کنیم از پیش تعیین کردن الزامات کلاس Mediator و مشخص کردن وظیفه متد ها می باشد همچنین اگر زمانی بخواهیم در کلاس های Mediator دست ببریم براحتی امکان این کار را داشته باشیم.
4.2 نمونه ی دنیای واقعی
در دنیای واقعی نیز یک نمونه ی مشهود در فرودگاه ها دیده می شود. طبق آنچه که در مورد آن بحث شد ساختار را به این گونه می توان منتقل کرد که هر هواپیما یک کامپوننت بوده و فرودگاه رابط کاربری Mediator، برج مراقبت نیز نقش ConcreteMediator را خواهد داشت. بدیهی است که خلبان هواپیما های مختلف با یکدیگر ارتباط مستقیم ندارند و برای فرود یا بلند شدن از باند فرودگاه با برج مراقبت ارتباط برقرار می کنند.
مسئولین ترافیک هوایی را در رادار مشاهده می کنند که کدام هواپیما کجاست و آماده ی پرواز و یا فرود می باشد و وضعیت آن را مشخص می کنند. خواه اینکه ممکن است از یک یا چند باند برای نشستن یا بلند شدن استفاده شود برج مراقبت هر هواپیما را از وضعیت موجود با خبر می کنند و با اولویت بندی کردن نوبت پروازها، ترافیک را کنترل می کند. با توجه به اینکه مثال گفته شده می تواند از ساختار اصلی و عملکرد یک الگوی رفتاری Mediator پیروی کند مشاهده می کنیم که با مشخص کردن مسئولیت های بخش های گوناگون یک سیستم حمل و نقل به آن سازماندهی داده و در راستای ایجاد نظم از وقوع پیچیدگی و حادثه جلوگیری شده است.
جمع بندی
در این مقاله به طور خلاصه به بررسی الگوی طراحی "Mediator" پرداختیم. این الگو وظیفه برقراری و کنترل بین چند کامپوننت را دارد به گونه ای که این اجزا با یکدیگر ارتباط مستقیم نداشته باشند و حتی به محتوای یکدیگر دسترسی و اطلاعی نداشته باشند. هدف اصلی این الگو از بین بردن وابستگی های مشترک بین مجموعه ای از اجزا در یک سیستم است و در ازاء از بین بردن این وابستگی ها همه ی اجزا مربوطه به جای وابستگی های قبلی خود به یک کلاس واحد و میانی تحت عنوان "Mediator" وابسته خواهند شد.
منابع
- Dive Into DESIGN PATTERNS by Alexander Shvets – digital e-book – published by refactoring.guru 2018
- https://refactoring.guru/design-patterns/mediator
- https://sourcemaking.com/design_patterns/mediator