ویرگول
ورودثبت نام
حسین نریمانی راد
حسین نریمانی رادبرنامه نویس GIS | برنامه نویس Back-end
حسین نریمانی راد
حسین نریمانی راد
خواندن ۳ دقیقه·۴ ماه پیش

الگوی طراحی استراتژی (Strategy deisgn pattern)

بسم الله

سلام

مشکل یادگیری #الگوهای_طراحی (design pattern) در قالب مثال‌هایی با کلاس‌های «Foo» و «Bar» یا کلاس‌های «Vehicle»، «Bus»، «Bicycle» و «Car»، اینه که بعدا توی مدل‌سازی‌ها، ذهن به سختی می‌تونه متناظر این مفاهیم رو توی کار پیدا کنه به خصوص این که همیشه مفاهیم به این شفافی نیستن و ذهن به تمرین‌های انتزاعی‌تری نیاز داره. به همین دلیل مثال‌هایی که آدم از روی تجربه باهاشون برخورد می‌کنه می‌تونن تمرین خوبی برای یادگیری بهتر این الگوها باشن.

مساله چی بود؟

لازم بود که نقطه/خط/چندضلعی رو به صورت عکسی رندر کنم (یعنی به عکس تبدیل کنم). برا این کار حداقل ۴ روش رندر وجود داشت که این‌جا مهم نیست اونا چی هستن. خب اولین چیزی که به ذهن ما می‌رسه اینه که بیاییم و یه enum برا روش‌های مختلف تعریف کنیم و بر اساس اون توی کد رندر رو انجام بدیم (شکل زیر):

رندر کردن نقطه/خط/چندضلعی بر اساس روش رندرینگ
رندر کردن نقطه/خط/چندضلعی بر اساس روش رندرینگ

این کد یه مجموعه نقطه/خط/چندضلعی رو در قالب feature می گرفت و یه عکس تولید می‌کرد. همه چی خوب بود. تا این که کندی سرعت اجرای این رندرینگ‌ها وقتی تعداد شکل‌های هندسی زیاد می‌شد اذیت کننده شد. برا همین مجبور شدیم یه روش رو امتحان کنیم و اون این بود که صفحه مانیتور رو به چندین تایل (Tile) با سایز ۲۵۶*۲۵۶ پیکلس تقسیم کردیم و رندرینگ هر تایل که تموم می شد به کاربر اونو نمایش می‌دادیم. هر چند که در مجموع ممکن بود رندر شدن کل تایل‌ها زمان بیش‌تری از رندرینگ یک‌باره تمام صفحه ببره ولی چون اولین تایل سریع‌تر نمایش داده می‌شد، کاربر احساس بهتری داشت که سیستم داره یه کاری انجام می‌ده. اما برای این روش تایل-مبنا هم ما مجبور شدیم مجدد همون switch بالا رو استفاده کنیم! پس تا این جا دو تا متد داریم که هر دو از یه switch استفاده کردن.

مشکل کجاست؟

فرض کنید غیر از روش‌های «رندرینگ یک‌باره تمام صفحه» و «رندرینگ تایل-مبنا» یه روش دیگه هم در آینده اضافه بشه اون وقت مجدد این switch‌رو باید استفاده کنیم. از طرفی اگه به خود روش‌های رندرینگ هم یه چیزی اضافه بشه (مثلا Approach5 اضافه بشه) اون وقت باید یادمون باشه کجاها روی اون enum ما switch گذاشتیم و همه switch ها رو اصلاح کنیم.

الگوی استراتژی چطوری می‌تونه کد ما رو تمیز کنه؟

همیشه وقتی برای انجام یه کاری چند روش (استراتژی) مستقل از هم وجود داره به یاد الگوی استراتژی بیفتید. این الگو، تصمیم‌گیری (کد switch) در مورد این که کدوم روش استفاده بشه رو به عهده یه کلاس به اسم Context می‌ذاره و سایر جاها همه از اون استفاده می‌کنن و این طوری از تکرار کد جلوگیری می‌کنه.

تصمیم‌گیری روش رندرینگ در کلاس Context با توجه به تنظیمات لایه (ToRasterTechnique)
تصمیم‌گیری روش رندرینگ در کلاس Context با توجه به تنظیمات لایه (ToRasterTechnique)

حالا جاهای مختلف کد چطوری از این استفاده می‌کنن؟ (شکل زیر) همون طور که می‌بینید دیگه به اون switch نیازی نیست و در واقع تصمیم‌گیری روش رندرینگ اصلا وظیفه‌ای نیست که بخواد توی متدهای مختلف تکرار بشه بلکه به صورت متمرکز بر عهده کلاس کانتکس هست.

حذف کد switch و استفاده از کلاس Context برای انتخاب استراتژی رندرینگ
حذف کد switch و استفاده از کلاس Context برای انتخاب استراتژی رندرینگ

جمع‌بندی

  • وقتی با مساله‌ای روبرو هستید که چند روش مستقل از هم دیگه داره و قرار نیست این روش‌ها با هم ترکیب بشن، احتمالا الگوی استراتژی به کار میاد.

  • وقتی کدهای switch که در مورد انتخاب روش دارن تصمیم‌گیری می کنن چند جا تکرار بشن احتمالا الگوی استراتژی به کار میاد.

  • الگوی استراتژی با انتقال کد تصمیم‌گیری در مورد روش انتخابی از متدهای مختلف به یه کلاس واحد (Context)، به رعایت اصل Single Responsibility (SRP) برای اون متدها کمک می‌کنه.

  • الگوی استراتژی باعث می شه با اضافه شدن روش جدید، فقط یه switch رو اصلاح کنید و لازم نباشه بگردید همه جا رو اصلاح کنید. این کار به رعایت اصل Open/Closed Principle (OCP) برای اون متدها کمک می‌کنه چون هم اون متدها تغییری نمی‌کنن و هم امکان اضافه شدن روش جدید هست. تنها جایی که تغییر می‌کنه کلاس Context هست که اونم وظیفه اصلیش همینه.

  • علاوه بر همه مزایای بالا، با تعریف یه تابع واحد Render توی کلاس strategy باعث شد که همه این متدها از نظر ورودی یکسان‌سازی بشن. این کار باعث شد که یه سری تبدیلات دیگه توی این متدها انجام نشه و این جا هم به رعایت SRP برا خود این متدها کمک کرد در حالی که توی نسخه‌های قدیمی این قید وجود نداشت.

  • با شکسته شدن کدها توی کلاس‌ها و فایل‌های کوچیک‌تر، شانس ایجاد conflict زمان merge شدن کدها هم کم‌تر می‌شه و به این ترتیب کار تیمی ساده‌تر می‌شه.

استراتژیdesign patternالگوهای طراحیکد تمیزکار تیمی
۰
۰
حسین نریمانی راد
حسین نریمانی راد
برنامه نویس GIS | برنامه نویس Back-end
شاید از این پست‌ها خوشتان بیاید