الگوی طراحی command
شناسه پست: 3150
بازدید: 833

الگوی Command، یک الگوی طراحی رفتاری است که میتوانیم از آن برای تبدیل یک request به یک آبجکت که شامل تمام اطلاعات مربوط به آن request است استفاده کنیم.

الگوی طراحی Command در #C کاملا محبوب است، به خصوص زمانی که می خواهیم اجرای یک request را به تأخیر بیندازیم یا در صف قرار دهیم یا زمانی که می خواهیم عملیات خود را ردگیری کنیم. علاوه بر این، این امکان ردگیری کردن، امکان undo کردن عملیات را نیز به ما میدهد.

این مقاله، بخشی از مجموعه آموزشی زیر است:

سورس کد در این لینک موجود است: الگوی طراحی Command – سورس کد.

برای مشاهده لیست کامل مقالات این مجموعه آموزشی، الگوهای طراحی #C را بررسی کنید.

این مقاله، به قسمتهای زیر تقسیم میشود:

پیاده سازی الگوی طراحی Command

الگوی طراحی Command، شامل کلاس Invoker، کلاس/اینترفیس Command، کلاسهای Concrete command و کلاس گیرنده (Receiver) میباشد. با این تفسیر، در مثال خود، ما از همین ساختار طراحی پیروی می کنیم.

بنابراین، کاری که می‌خواهیم انجام دهیم این است که یک برنامه ساده بنویسیم که در آن قیمت محصول را تغییر دهیم که الگوی طراحی Command را پیاده‌سازی کند.

همانطور که گفته شد، بیایید با کلاس گیرنده محصول شروع کنیم، که باید business logic پایه را در برنامه ما دربر داشته باشد:

بنابراین این کلاس receiver ما است که کاملا یک منطق ساده و واضح دارد. ما اینجا فقط قیمت محصول را افزایش یا بر حسب شرط کاهش میدهیم. در آخر، ما متد ToString را داریم که قادر به چاپ و نمایش اطلاعات آبجکت ما است.

حالا کلاس Client میتواند کلاس Product را نمونه سازی کرده و action های مورد نیاز را اجرا کند. اما فرض الگوی طراحی Command بر این اساس است که ما بهتر است از کلاس receiver به طور مستقیم استفاده نکنیم. بلکه بهتر است تمام جزییات request را به داخل یک کلاس ویژه به نام Command استخراج کنیم.

و این دقیقا کاری است که ما قصد داریم انجام دهیم.

اولین کاری که ما میخواهیم انجام دهیم اضافه کردن اینترفیس ICommand است:

فقط برای تعیین نمودن اقدامات اصلاح قیمت خود، می‌خواهیم یک شمارنده ساده به نام PriceAction اضافه کنیم:

در آخر، کلاس ProductCommand را اضافه میکنیم:

همانطور که میبینیم، کلاس ProductCommand تمام اطلاعات مربوط به request مورد نظر را در اختیار دارد و بر اساس آن، action مورد نیاز را اجرا میکند.

در ادامه، کلاس ModifyPrice را اضافه میکنیم که به عنوان Invoker عمل میکند:

این کلاس میتواند با هر command  که اینترفیس ICommand را پیاده سازی میکند کار کند و تمام عملیات را نیز ذخیره کند.

حالا ما میتوانیم کار با قسمت client را شروع کنیم:

نتیجه باید به صورت زیر باشد:

پیاده سازی الگوی Command

عالی. ما اینجا میتوانیم ترتیب اجرای action ها و قیمت درست بعد از اصلاحیه ها را ببینیم.

با در نظر گرفتن این موضوع که ما action های خود را در کلاس Invoker ردگیری میکنیم، میتوانیم در صورت نیاز، از آن برای Undo کردن عملیات خود نیز استفاده کنیم.

بنابراین آن را امتحان میکنیم.

پیاده سازی عملیات Undo در الگوی طراحی Command

برای پیاده سازی عملیات Undo، بیایید با تغییرات اینترفیس ICommand شروع کنیم:

سپس کلاس ProductCommand را با اضافه کردن متد UndoAction تغییر میدهیم:

البته ما باید با اضافه کردن متد UndoActions، کلاس ModifyPrice را نیز اصلاح کنیم:

لطفاً توجه داشته باشید که ما از متد Linq Reverse استفاده نمی کنیم بلکه از ()Enumerable.Reverse استفاده می کنیم. این به این دلیل است که متد Linq لیست ما را تغییر می دهد و ما نمی خواهیم این اتفاق بیفتد. تنها چیزی که می خواهیم فقط یک لیست معکوس است اما بدون تغییر در خود لیست اصلی.

حال، وقتی کلاس Client متد UndoActions را فراخوانی می‌کند، تمام عملیات‌های درون list را پیمایش می‌کند و عملیات متضاد با عملیات انجام شده قبلی را اجرا میکند.

اجازه دهید تا آن را امتحان کنیم:

نتیجه:

پیاده سازی undo در الگوی Command

همه چیز طبق انتظار به درستی کار میکند.

بهبود Solution

ما الگوی طراحی Command را به داخل برنامه خود پیاده سازی کردیم و هیچ مشکل خاصی در آن وجود ندارد. اما یک نقص در Solution ما وجود دارد که مربوط به الگوی Command نمیشود، بلکه در کل مربوط به business logic ما میشود.

برای مثال، اگر کاهش قیمت را از 25 به 2500 تغییر میدادیم، چه اتفاقی می افتاد؟ خب، ما اعتبارسنجی مربوطه را در متد DecreasePrice انجام داده ایم و از این رو، این اعتبارسنجی باعث میشود که این نوع کاهش قیمت، در نتیجه تاثیری نداشته باشد و حق با شماست. اما بر روی Undo action ها تاثیر میگذارد.

ببینیم که چطور این تاثیر را میگذارد:

نتیجه به این صورت خواهد بود:

نقض undo الگوی طراحی Command

همانطور که می بینید، قیمت ما کاهش نیافته است، اما عملیات در فروشگاه ما، به عنوان یک عملیات انجام شده ثبت شده است که باعث شده تا عمل Undo برای آن انجام شود که نباید این اتفاق می افتاد.

بنابراین، بیایید آن را برطرف کنیم.

اولین کاری که قرار است انجام دهیم اصلاح متد DecreasePrice در کلاس Product است:

حالا میتوانیم کلاس ProductCommand را نیز اصلاح کنیم:

و تمام. حال اگر برنامه خود را با مقدار کاهش 2500 اجرا کنیم، نتیجه درست خواهد بود:

حل undo الگوی Command

همه چیز به خوبی پیش رفت.

نتیجه گیری

اگرچه الگوی طراحی Command باعث ایجاد پیچیدگی در کد ما میشود، اما می تواند بسیار مفید باشد.

با آن می‌توانیم کلاس‌هایی را که عملیات را invoke می‌کنند از کلاس‌هایی که این عملیات را انجام می‌دهند جدا کنیم. علاوه بر این، اگر بخواهیم command های جدیدی را معرفی کنیم، لازم نیست کلاس‌های موجود را تغییر دهیم. در عوض، ما فقط می توانیم این کلاس های command جدید را به پروژه خود اضافه کنیم.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید