فرض کنید رفتید رستوران ، به گارسون سفارشتون رو میدید ، گارسون سفارش رو میبره تحویل آشپزخونه و بر حسب سفارشتون یکی آمادهاش میکنه ، اگه کباب بخواید ، کباب زن براتون کباب میذاره رو منقل و اگه پیتزا بخواید یک نفر دیگه اون مسئول پخت پیتزا با فِر میشه ، الگویِ طراحی Command دقیقا همینه !
این الگو جزو طبقهبندی Behavioral ها حساب میشه چون به رفتارهای الگوریتم و ارتباط اجزا با هم کار داره ، ما در این الگو چند بخش داریم :
یک interface که شامل تعریفِ توابع اصلی هستند ، مثلا تابع execute ، یا تابع undo برای اینکه Command ای که اجرا کردید رو به حالت قبل برگردونید (یا هر تابعی که شما به نظرتون نیازه مثل redo و ... ، یا فرضا دارید برای کپی پیست یک Command درست میکنید و اونا رو هم میتونید لحاظ کنید ، من در کدی که در این مقاله میارم فقط execute و undo رو مثال میزنم)
معنی Concrete میشه "بتن" ، پس این کلاس بدنه یک Command هست ، یعنی ما بر اساس Command این کلاس رو میسازیم و توابعی که در Command داشتیم رو بر حسب این کلاس پیاده سازی میکنیم ، چرا میگم "بر حسب این کلاس" ؟ چون میتونیم انواع مختلف از این کلاس رو داشته باشیم (در مثال متوجه میشید)
کلاسی که Command رو به درخواست مورد نظر میرسونه ، مثلا یک ریموت کنترل میشه یک Invoker
درخواست کننده اون Command ، یعنی کسی که در انتها Command رو دریافت میکنه و متناظر اون یک تغییری در خودش میده
برنامهای مینویسیم که بتواند رنگِ کلاسی به اسم Light را بر حسب Command به سه نور قرمز ، آبی و سفید تغییر دهد ، برای این کار اول از همه همهی توابع مورد نیاز برای یک Command رو در یک Interface تعریف میکنیم :
حالا نیاز داریم که کلاس Receiver رو که همون Light میشه بسازیم ، این کلاس یک color در خودش داره و تعدادی تابع برای تغییر رنگِ color :
حالا باید ConcreteCommand ها رو بسازیم ، من در این مثال سه ConcreteCommand میسازم برای هر رنگ و این سه کلاس رو از کلاسی به اسم LightCommandMother مشتق میکنم ، LightCommandMother یک کلاس abstact هست که بدنه تابع undo در اون پیاده شده و یک Receiver هم به عنوان ورودی میگیره ، این کلاس یک اِلِمان به عنوان lastStatus داره که رنگِ حالت قبلی رو در خودش داره (البته برای مثالهای پیچیده نباید این طوری بنویسید و به جاش میتونید از شئ یک clone بسازید و در تابع undo کلِ اون شئ رو درون شئ جدید بریزید) ، باقی ConcreteCommand ها از این کلاس مشتق میشن و تابع execute درون اونها پیاده میشه :
حالا نیاز به یک Invoker داریم (invoke در لغت به معنی فراخوانی هست) که اسمشو میذاریم RemoteControl ، در این کلاس یک Stack (پشته) از Commandها داریم و یک تابع pressButton ، در ورودیِ pressButton یک Command قرار میگیره که اون رو execute کرده و درون stack قرار میده ، در این کلاس تابع undoButton عمل undo رو انجام میده ، اگر stack خالی بود که هیچی وگرنه آخرین Command رو pop میکنه و تابع undo اونو صدا میزنه :
و درآخرم نیاز به کدِ Client هست که بیاد از چیزایی که تا الان تعریف کردیم استفاده کنه ، مثلا چندبار دکمه فشار بده و یکبار هم undo کنه :
و تمام !
حالا چه زمانهایی باید از این الگو استفاده کنیم ؟
باقی مقالات در مورد الگویهای طراحی رو در این مقاله بخونید .
من رو در لینکدین و اینستاگرام دنبال کنید ???
اگه دوست داشتید میتونید به صفحه Spotify بنده هم برید و موسیقی های منو گوش بدید ???