مدیریت و کنترل (Command)
هـــدف
فرمان یک الگوی طراحی رفتاری است که یک درخواست را به یک شیء مستقل تبدیل میکند که تمام اطلاعات مربوط به درخواست را در خود جای میدهد. این تبدیل به شما امکان میدهد درخواستها را به عنوان آرگومانهای متد منتقل کنید، اجرای درخواست را تأخیر یا صف کنید و از عملیاتهای قابل بازگشت پشتیبانی کنید.
مـسئـــلـه
تصور کنید که در حال کار روی یک برنامه ویرایشگر متن جدید هستید. کار فعلی شما ایجاد یک نوار ابزار با مجموعهای از دکمهها برای عملیاتهای مختلف ویرایشگر است. شما یک کلاس دکمه بسیار مرتب ایجاد کردید که میتواند برای دکمههای روی نوار ابزار و همچنین برای دکمههای عمومی در دیالوگهای مختلف استفاده شود.
در حالی که همه این دکمهها شبیه به هم هستند، همه آنها باید کارهای مختلفی انجام دهند. کد برای هندلرهای مختلف کلیک این دکمهها را کجا قرار میدهید؟ سادهترین راه حل ایجاد تعداد زیادی زیرکلاس برای هر مکان استفاده از دکمه است. این زیرکلاسها حاوی کدی خواهند بود که باید هنگام کلیک روی دکمه اجرا شود.
قبل از مدت طولانی، متوجه خواهید شد که این رویکرد عمیقاً ناقص است. اولاً، تعداد زیادی زیرکلاس دارید و این خوب خواهد بود اگر در هر بار اصلاح کلاس پایه Button خطر شکستن کد در این زیرکلاسها را نداشته باشید. به زبان ساده، کد GUI شما به طور ناخوشایندی به کد ناپایدار منطق تجاری وابسته شده است.
و اینجا زشتترین قسمت است. برخی عملیات، مانند کپی/پیست متن، باید از مکانهای مختلف فراخوانی شوند. به عنوان مثال، یک کاربر میتواند روی یک دکمه کوچک “کپی” روی نوار ابزار کلیک کند، یا چیزی را از طریق منوی زمینه کپی کند، یا فقط Ctrl+C را روی صفحه کلید فشار دهد.
در ابتدا، هنگامی که برنامه ما فقط نوار ابزار را داشت، قرار دادن پیادهسازی عملیاتهای مختلف در زیرکلاسهای دکمه خوب بود. به عبارت دیگر، داشتن کد کپی متن در زیرکلاس CopyButton خوب بود. اما سپس، هنگام پیادهسازی منوی زمینه، میانبرها و موارد دیگر، باید کد عملیات را در کلاسهای متعدد تکرار کنید یا منوها را به دکمهها وابسته کنید که این گزینه حتی بدتر است.
راهــکــــار
طراحی نرمافزار خوب اغلب مبتنی بر اصل جداسازی نگرانیها است که معمولاً منجر به شکستن یک برنامه به لایهها میشود. رایجترین مثال: یک لایه برای رابط کاربری گرافیکی و یک لایه دیگر برای منطق تجاری. لایه GUI مسئول ارائه یک تصویر زیبا روی صفحه، ضبط هر ورودی و نشان دادن نتایج کارهای کاربر و برنامه است. با این حال، هنگام انجام کاری مهم مانند محاسبه مسیر ماه یا تهیه یک گزارش سالانه، لایه GUI کار را به لایه زیرین منطق تجاری واگذار میکند.
در کد ممکن است به این شکل باشد: یک شیء GUI یک متد از یک شیء منطق تجاری را فراخوانی میکند و برخی آرگومانها را به آن منتقل میکند. این فرآیند معمولاً به عنوان یک شیء که درخواست دیگری را ارسال میکند توصیف میشود.
الگوی فرمان پیشنهاد میکند که اشیاء GUI این درخواستها را به طور مستقیم ارسال نکنند. در عوض، باید تمام جزئیات درخواست، مانند شیء مورد فراخوانی، نام متد و لیست آرگومانها را به یک کلاس فرمان جداگانه استخراج کنید که یک متد واحد برای فعال کردن این درخواست دارد.
اشیاء فرمان به عنوان پیوند بین اشیاء مختلف GUI و منطق تجاری عمل میکنند. از این پس، شیء GUI نیازی ندارد بداند کدام شیء منطق تجاری درخواست را دریافت میکند و چگونه پردازش میشود. شیء GUI فقط فرمان را فعال میکند و فرمان تمام جزئیات را مدیریت میکند.
قدم بعدی این است که دستورات خود را به گونهای پیادهسازی کنید که رابط یکسانی داشته باشند. معمولاً فقط یک متد اجرا وجود دارد که هیچ پارامتری نمیگیرد. این رابط به شما امکان میدهد از فرمانهای مختلف با یک فرستنده درخواست استفاده کنید، بدون اینکه آن را به کلاسهای مشخص فرمان متصل کنید. به عنوان یک مزیت، اکنون میتوانید اشیاء فرمان مرتبط با فرستنده را تغییر دهید و رفتار فرستنده را در زمان اجرا تغییر دهید.
ممکن است متوجه یک قطعه گمشده از پازل شده باشید که پارامترهای درخواست است. یک شیء GUI ممکن است برخی پارامترها را به شیء لایه تجاری ارائه داده باشد. از آنجایی که متد اجرای فرمان هیچ پارامتری ندارد، چگونه میتوانیم جزئیات درخواست را به گیرنده منتقل کنیم؟ به نظر میرسد فرمان باید یا با این دادهها از پیش پیکربندی شده باشد یا بتواند آن را به تنهایی دریافت کند.
بیایید به ویرایشگر متن خود بازگردیم. پس از اعمال الگوی فرمان، دیگر نیازی به تمام آن زیرکلاسهای دکمه برای پیادهسازی رفتارهای مختلف کلیک ندارید. کافی است یک فیلد واحد را در کلاس پایه Button قرار دهید که مرجعی به یک شیء فرمان ذخیره میکند و دکمه را وادار کنید که آن فرمان را هنگام کلیک اجرا کند.
شما یک دسته کلاس فرمان برای هر عملیات ممکن پیادهسازی خواهید کرد و آنها را با دکمههای خاص، بسته به رفتار مورد نظر دکمهها، مرتبط خواهید کرد.
عناصر دیگر GUI، مانند منو، میانبرها یا کل دیالوگها، میتوانند به همین روش پیادهسازی شوند. آنها به یک فرمان مرتبط خواهند شد که هنگام تعامل یک کاربر با عنصر GUI اجرا میشود. همانطور که احتمالاً تاکنون حدس زدهاید، عناصر مرتبط با همان عملیات به همان فرمانها مرتبط خواهند شد و از هرگونه تکرار کد جلوگیری میکنند.
در نتیجه، فرمانها یک لایه میانی مناسب میشوند که اتصال بین لایههای GUI و منطق تجاری را کاهش میدهد. و این تنها بخشی از مزایایی است که الگوی فرمان میتواند ارائه دهد!
مقایسه با دنیای واقعی
ترجمه:
پس از یک پیادهروی طولانی در شهر، به یک رستوران خوب میرسید و در کنار پنجره مینشینید. یک پیشخدمت دوستانه به سراغ شما میآید و به سرعت سفارش شما را میگیرد و آن را روی یک تکه کاغذ مینویسد. پیشخدمت به آشپزخانه میرود و سفارش را روی دیوار میچسباند. پس از مدتی، سفارش به دست آشپز میرسد، که آن را میخواند و مطابق آن غذا را میپزد. آشپز غذا را همراه با سفارش روی یک سینی قرار میدهد. پیشخدمت سینی را کشف میکند، سفارش را بررسی میکند تا مطمئن شود همه چیز همانطور که میخواستید است و همه چیز را به میز شما میآورد.
سفارش کاغذی به عنوان یک فرمان عمل میکند. تا زمانی که آشپز آماده سرو آن باشد، در صف باقی میماند. سفارش حاوی تمام اطلاعات مرتبط مورد نیاز برای پخت غذا است. این به آشپز اجازه میدهد تا بلافاصله شروع به پختن کند، بدون اینکه برای روشن کردن جزئیات سفارش مستقیماً به شما مراجعه کند.
ســاخــتـــار
برای مطـالعـه متن کامل مقالــه، مجموعه کــــدها، نحوه پیاده سازی، مزایا و معایب و روابط با الگوهای دیگر، ایــنــجـــا کلیک کنید.