الگویِ طراحی Command (جاوا و کاتلین)

فرض کنید رفتید رستوران ، به گارسون سفارشتون رو می‌دید ، گارسون سفارش رو می‌بره تحویل آشپزخونه و بر حسب سفارشتون یکی آماده‌اش می‌کنه ، اگه کباب بخواید ، کباب زن براتون کباب می‌ذاره رو منقل و اگه پیتزا بخواید یک نفر دیگه اون مسئول پخت پیتزا با فِر میشه ، الگویِ طراحی Command دقیقا همینه !

برای شما

این الگو جزو طبقه‌بندی Behavioral ها حساب میشه چون به رفتار‌های الگوریتم و ارتباط اجزا با هم کار داره ، ما در این الگو چند بخش داریم :

Command

یک interface که شامل تعریفِ توابع اصلی هستند ، مثلا تابع execute ، یا تابع undo برای اینکه Command ای که اجرا کردید رو به حالت قبل برگردونید (یا هر تابعی که شما به نظرتون نیازه مثل redo و … ، یا فرضا دارید برای کپی پیست یک Command درست می‌کنید و اونا رو هم می‌تونید لحاظ کنید ، من در کدی که در این مقاله میارم فقط execute و undo رو مثال می‌زنم)

ConcreteCommand

معنی Concrete میشه “بتن” ، پس این کلاس بدنه یک Command هست ، یعنی ما بر اساس Command این کلاس رو می‌سازیم و توابعی که در Command داشتیم رو بر حسب این کلاس پیاده سازی می‌کنیم ، چرا میگم “بر حسب این کلاس” ؟ چون می‌تونیم انواع مختلف از این کلاس رو داشته باشیم (در مثال متوجه می‌شید)

Invoker

کلاسی که Command رو به درخواست مورد نظر می‌رسونه ، مثلا یک ریموت کنترل میشه یک Invoker

Receiver

درخواست کننده اون Command ، یعنی کسی که در انتها Command رو دریافت می‌کنه و متناظر اون یک تغییری در خودش می‌ده

صورت مساله

برنامه‌ای می‌نویسیم که بتواند رنگِ کلاسی به اسم Light را بر حسب Command به سه نور قرمز ، آبی و سفید تغییر دهد ، برای این کار اول از همه همه‌ی توابع مورد نیاز برای یک Command رو در یک Interface تعریف می‌کنیم :

https://gist.github.com/sasssass/174e3b579b7304c9cb4cefc0b15db732

حالا نیاز داریم که کلاس Receiver رو که همون Light میشه بسازیم ، این کلاس یک color در خودش داره و تعدادی تابع برای تغییر رنگِ color :

https://gist.github.com/sasssass/852940f20af61bccbd57afb2424b83f9

حالا باید ConcreteCommand ها رو بسازیم ، من در این مثال سه ConcreteCommand می‌سازم برای هر رنگ و این سه کلاس رو از کلاسی به اسم LightCommandMother مشتق می‌کنم ، LightCommandMother یک کلاس abstact هست که بدنه تابع undo در اون پیاده شده و یک Receiver هم به عنوان ورودی می‌گیره ، این کلاس یک اِلِمان به عنوان lastStatus داره که رنگِ حالت قبلی رو در خودش داره (البته برای مثال‌های پیچیده نباید این طوری بنویسید و به جاش می‌تونید از شئ یک clone بسازید و در تابع undo کلِ اون شئ رو درون شئ جدید بریزید) ، باقی ConcreteCommand ها از این کلاس مشتق میشن و تابع execute درون اونها پیاده میشه :

https://gist.github.com/sasssass/a8e1146c80aefa74f694e6b14284a2d9

حالا نیاز به یک Invoker داریم (invoke در لغت به معنی فراخوانی هست) که اسمشو می‌ذاریم RemoteControl ، در این کلاس یک Stack (پشته) از Commandها داریم و یک تابع pressButton ، در ورودیِ pressButton یک Command قرار می‌گیره که اون رو execute کرده و درون stack قرار می‌ده ، در این کلاس تابع undoButton عمل undo رو انجام می‌ده ، اگر stack خالی بود که هیچی وگرنه آخرین Command رو pop می‌کنه و تابع undo اونو صدا می‌زنه :

https://gist.github.com/sasssass/fbd9e1584eca9a1f5b8dc67a4cab25ef

و درآخرم نیاز به کدِ Client هست که بیاد از چیزایی که تا الان تعریف کردیم استفاده کنه ، مثلا چندبار دکمه فشار بده و یکبار هم undo کنه :

https://gist.github.com/sasssass/066dfdaab038d0b6685c73d7e745d3e2

و تمام !

حالا چه زمان‌هایی باید از این الگو استفاده کنیم ؟

  1. زمانی که به سابقه و history از درخواست ها نیاز داریم (مثلا با stack)
  2. زمانی که نیاز داریم درخواست کننده‌ی Command اطلاعی در مورد پیاده‌سازی نداشته باشه (یعنی کد‌ها جدا باشن و پیاده‌سازی‌ها مخفی شده باشند)
  3. لایه‌بندی ایجاد شده در این الگو موجب میشه بعدا اگه لازم شد بهتر و راحت‌تر و دستِ باز تر تغییرات مورد نیازمون رو در کد انجام بدیم
  4. و …

باقی مقالات در مورد الگوی‌های طراحی رو در این مقاله بخونید .

من رو در لینکدین و اینستاگرام دنبال کنید ???

اگه دوست داشتید می‌تونید به صفحه Spotify بنده هم برید و موسیقی های منو گوش بدید ???

نویسنده مطلب: Ali Shobeyri

منبع مطلب

به فکر سرمایه‌گذاری هستی؟

با هر سطحی از دانش در سریع‌ترین زمان با آموزش گام به گام، سرمایه گذاری را تجربه کن. همین الان میتونی با لینک زیر ثبت نام کنی و ۱۰ درصد تخفیف در کارمزد معاملاتی داشته باشی

ثبت نام و دریافت جایزه
ممکن است شما بپسندید
نظر شما درباره این مطلب

آدرس ایمیل شما منتشر نخواهد شد.