همانطور که مستحضر هستید کلمهی Polymorphism به معنای چندریختی است. در برنامهنویسی شیءگرا پلی مورفیسم اغلب به عنوان یک تغییردهنده رفتار یا یک واسط چند متدی مطرح میشود.
در زبان برنامهنویسی #C پلی مورفیسم به سه شکل ممکن پیادهسازی میشود:
- استفاده از متدهای virtual و override کردن آنها در کلاس فرزند
- بهرهگیری از متدهای abstract در کلاس والد
- بهرهگیری از قابلیت واسطها یا Interfaceها ( واسطها در فصول بعدی به تفصیل توضیح داده خواهند شد)
متدهای virtual
فرض کنید یک کلاس والد به نام Shape دارید که در آن متدی به نام Draw تعریف شده است. متد Draw وظیفهی ترسیم یک شیء یا شکل را به عهده دارد. این متد در تمام کلاسهایی که از این کلاس مشتق میشوند قابل استفاده است. بنابراین کلاس Shape را به صورت زیر مینویسم:
حال باید کلاسهای فرزند مرتبط با این کلاس را تعریف کنیم بنابراین سه کلاس به نامهای Triangle و Rectangle و Circle را تعریف میکنیم که هر سه از کلاس والد یعنی Shape مشتق شده اند:
هر سه کلاسی که در فوق تعریف کردیم میتوانند از متد Draw استفاده کنند زیرا این متد در کلاس اصلی والد تعریف شده است. حال اگر شیءای بسازیم آنگاه:
در نهایت خروجی دستورات به صورت زیر است:
اما این خروجی مورد پسند نیست و باید برای هر کلاس یک شکل کشیده شود در نهایت برای رفع این مشکل متد موجود در کلاس والد را به صورت virtual تعریف کرده و آن را درون کلاس فرزند override میکنیم. بنابراین تغییراتی در کلاس والد داده و متد Draw را به صورت زیر تعریف میکنیم:
حال همین تغییرات را درون کلاسهای فرزند انجام میدهیم:
حال خروجی دستورات فوق به صورت زیر اصلاح میشوند:
همچنین اگر از کلمهی کلیدی base درون متد کلاس فرزند استفاده کنیم محتوا و متد کلاس پایه نمایش داده خواهد شد:
استفاده از روش virtual و override تنها به متدها ختم نمیشود بلکه میتوان برای خصوصیات یا Property ها نیز این کار را انجام داد:
معرفی کلاسها و متدهای abstract و sealed
هنگامیکه یک برنامه را مینویسیم و کلاسها و اعضای آن را مشخص میکنیم باید برای استفاده از کلاسها یک سری محدودیت بگذاریم. مثلا یک کلاس پایه داریم که این کلاس نباید توسط سایر کلاس ها مورد استفاده قرار بگیرد و تنها اعضای آن کلاس و کلاس هایی که از آن به ارث بردهاند، توانایی دسترسی به متدها و اعضای آن را دارند یا مثلا کلاسی را ایجاد کردهایم که با اعمال محدودیتهایی اجاره ایجاد کلاس فرزند از آن را نمیدهیم. برای اعمال همچین محدودیتهایی از کلاسها یا متدهایی با فرم abstract یا sealed استفاده میشود.
کلاسها و اعضاء abstract
به مثال قبلی باز میگردیم که یک کلاس والد به نام Shape داشتیم و از روی این کلاس سه فرزند ساخته بودیم:
اگر به مثال بالا مراجعه کنید متوجه میشوید که کلاس Shape عملا برای ما کاربردی ندارد. به عبارت دیگر در طول برنامهی اصلی از آن استفاده نشده است. یعنی باید محدودیتی اعمال کنیم که از روی کلاس Shape شیءای ایجاد نشود. برای اینکار کافیست کلاس Shape را از نوع abstract تعریف کنیم. بنابراین طی یک تعریف کلی برای abstract داریم:
اگر کلاسی به صورت abstract ایجاد شود، در طول برنامه نمیتوان از روی آن شیءای ساخت.
به مثال زیر توجه کنید:
حال اگر بخواهیم از روی کلاس Shape یک شیء ایجاد کنیم با خطای زیر مواجه میشویم:
Cannot create an instance of the abstract class
یعنی نمیتوان از روی کلاسهایی که به صورت abstract تعریف شدهاند شیءای ایجاد کرد.
اما کاربردهای بیشتری از کلاس abstract انتظار میرود. در کلاسهای abstract میتوان به طور مشابه متدهایی را تعریف کرد که به صورت abstract باشند. این متدها تنها شامل signature هستند یعنی بدنهای نداشته و پس از تعریف آنها به علامت ; ختم میشوند. درصورتیکه یک متد به صورت abstract تعریف شود بدین گونه است که حتما باید آن را جهت استفاده در طی برنامه یا کلاس دیگر override کنند. برای مثال یکبار دیگر کلاس Shape را بازنویسی میکنیم:
همانطور که ملاحظه میکنید متدی به نام Draw وجود دارد که بدنهای ندارد. علت این امر تعریف این متد به صورت abstract است. حال اگر کلاس فرزندی از کلاس Draw به ارث ببرد باید همواره متد درون آن به صورت abstract قرار بگیرد. بنابراین داریم:
کلاسها و اعضاء sealed
در بخش وراثت آموزش دادیم که همواره میتوان یک زنجیرهی وراثت در اختیار داشت مثلا کلاس B از کلاس A و کلاس C از کلاس B مشتق شود. حال درنظر بگیرید که میخواهیم به نحوی این زنجیرهی وراثت را قطع کنیم. برای اینکار باید کلاس موردنظر را از نوع sealed تعریف کنیم. بنابراین در طی یک تعریف کلی داریم:
کلاسهایی که به صورت sealed مورد استفاده قرار میگیرند، باعث حذف زنجیره وراثت میشوند.
به مثال زیر توجه کنید:
در این کد کلاس B از نوع sealed تعریف شده است و این موضوع بدین معناست که هیچ کلاس دیگری نمیتواند از کلاس B مشتق شود و یا متدها و ویژگیهایی را به ارث ببرد. به عنوان مثال اگر کد زیر را پیاده سازی کنیم:
آنگاه با خطای زیر روبهرو میشویم:
Cannot inherit from sealed class 'B'
بدین معنیست که شما نمیتوانید از یک کلاس که به صورت sealed تعریف شده است ویژگی یا متدی را به ارث ببرید.
یکی دیگر از کاربردهای عبارت sealed جلوگیری از override کردن یک متد است. به مثال زیر توجه کنید:
این مثال بدین صورت عمل میکند که اگر کلاسی از کلاس Rectangle مشتق شد، دیگر قابلیت override کردن متد Draw را نداشته باشد زیر در متد موجود در کلاس Rectangle، متد به صورت sealed تعریف شده است.
با مرور این فصل اطلاعات بسیار مفیدی در اختیار شما قرار میگیرد. شما با کلمات کلیدی virtual, override, abstract, sealed به صورت کامل آشنا شده و نحوهی اعمال محدودیتها به یک کلاس را فرا گرفتید. در فصل بعدی به توضیح مفصل واسطها (Interface) میپردازیم. با ما همراه باشید.
منبع: روکسو