قبل از پرداختن به توضیح مطالب این پست ٬ به توضیحاتی ابتدایی در مورد الگویهای طراحی (Design Patterns) میپردازیم.
الگوهای طراحی٬ راه حل هایی ثابتشده برای حل مشکلات رایج در برنامه نویسی شئ گرا هستند.
توضیحات ویکی پدیا:
در مهندسی نرمافزار، الگوی طراحی (Design Pattern) یک راهحل عمومی قابل تکرار برای مشکلات متداول در زمینه طراحی نرمافزار است. الگوی طراحی، یک طراحی تمامشده نیست که به صورت مستقیم بتواند تبدیل به کد منبع یا ماشین شود؛ بلکه، یک توضیح یا قالب برای حل یک مسئله در شرایط مختلف است. الگوها در واقع بهترین روش ممکن هستند که یک برنامهنویس میتواند در هنگام طراحی یک برنامه برای حل مشکلاتش از آنها استفاده کند.
الگوهای طراحی به ۳ دسته کلی تقسیم میشوند:
الگوی طراحی دکوراتور یکی از الگوهای طراحی ساختاری هست و امکان اضافه کردن عملکرد به اشیا را در زمان اجرا فراهم می کند.
توضیحات ویکی پدیا:
در برنامهنویسی شئ گرا، الگوی آذینگر یا دکوراتور (decorator) یک الگوی طراحی است که امکان افزودن رفتار (behavior) به یک شئ، را بهطور پویا (dynamic) یا ایستا (static) فراهم میسازد بی آنکه رفتار اشیاء دیگر از همان کلاس (که شئ مورد بحث از آن ساخته شده) دستخوش تغییر شوند. الگوی طراحی آذینگر معمولاً برای پایبندی به قاعدهٔ تک وظیفهای مورد استفاده قرار میگیرد چرا که این الگوی طراحی، امکان تقسیم عملکردها بین کلاسهای مختلف که هر کدام دغدغههای خاص را پوشش میدهند، فراهم میسازد.
حال برای مثال ٬ یک سناریوی فرضی را در نظر میگیریم:
ما یک شرکت خدمات وب داریم و میخواهیم یه سری خدمات رو به مشتریان ارائه بدیم, پس مسلما نیاز داریم تا قیمت این خدمات رو حساب کنیم. یکی از ابتداییترین سرویسها برای چنین شرکتی٬ میزبانی وب هست. اگر بخواهیم سادهترین حالت کد برای این کار رو در نظر بگیریم.. چیزی شبیه زیر داریم:
حالا حالتی رو در نظر بگیرید که میخواهیم قیمت میزبانی وب + ثبت دامنه رو حساب کنیم. شاید اولین راهی که به ذهن شما برسه ایجاد یک کلاس برای دریافت قیمت هر دو سرویس باشه. شبیه زیر:
ممکنه فکر کنید که خیلی خوب ٬ کدتون کار میکنه و این جور کد نوشتن هیچ مشکلی نداره... اما اگر کمی به تمام حالات ممکن که میشه این سرویسها رو با هم ترکیب کرد فکر کنیم٬ متوجه میشیم که حالات زیادی وجود دارند.
برای مثال حالتی رو در نظر بگیرید که در کنار ۲ سرویس قبلی٬ یه سرویس مدیریت نیم سرورها هم به موارد اضافه میشه:
همانطور که میبینید ٬ این سبک کد نوشتن به سادگی ما رو دچار مشکل میکنه. به چند علت:
خوب نمیشد اگر میتوانستیم این اشیا رو در حین زمان اجرا و بهطور مستقل بسازیم؟ و یک دکوراتور دقیقا همین قابلیت رو به ما میده...
و برای تبدیل کلاسها به دکوراتور:
پس کدی که باید داشته باشیم٬ به این شکله:
و در نهایت کلاس اولیه رو در کلاس دکوراتور میپیچیم و بصورت زیر استفاده میکنیم:
به این حالت ما میتونیم٬ این اشیا رو در حین زمان اجرا و کاملا پویا داشته باشیم.
با توضیحاتی که داده شد٬ ممکنه این سوال پیش بیاد که چه هنگام باید از این الگو و چه هنگام باید از وراثت استفاده کرد؟
به عنوان یه قاعده کلی مراقب استفاده از وراثت باشید. وراثت حتما جایگاه خودشو داره اما مراقب باشید که تمام عملکردهایی که ممکنه حتی بهشون نیاز هم نداشته باشید رو به کلاستون منتقل نکنید. در حالی که میتونید از الگوی کامپوزیت یا دکوراتور استفاده کنید.