درخواست های ارتباط
جستجو
لیست دوستان من
صندوق پیام
همه را دیدم
  • در حال دریافت لیست پیام ها
صندوق پیام
رویدادها
همه را دیدم
  • در حال دریافت لیست رویدادها
همه رویدادهای من
تخفیف های وب سایت
همه تخفیف ها

عضویت در

کانال تلگرام

توسینسو

اطلاعات مطلب
مدرس/نویسنده
حسین احمدی
امتیاز: 215942
رتبه:3
344
265
416
2833
حسین احمدی ، بنیانگذار TOSINSO ، توسعه دهنده وب و برنامه نویس ، بیش از 12 سال سابقه فعالیت حرفه ای در سطح کلان ، مشاور ، مدیر پروژه و مدرس نهادهای مالی و اعتباری ، تخصص در پلتفرم دات نت و زبان سی شارپ ، طراحی و توسعه وب ، امنیت نرم افزار ، تحلیل سیستم های اطلاعاتی و داده کاوی ... پروفایل کاربر

آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت هفدهم :: آشنایی با مفهوم Polymorphism

تاریخ 46 ماه قبل
نظرات 3
بازدیدها 4354
همانطور که در بخش قبل گفتیم وراثت یکی از اصلی ترین مباحث برنامه نویسی شئ گرا می باشد. در بخش قبلی با شیوه ارث بری از کلاس ها آشنا شدیم. یکی از مفاهیمی که در برنامه نویسی شئ گرا خیلی کاربرد دارد و وابسته به مفهوم وراثت است، چند ریختی یا Polymorphism است. در قسمت مقدمه برنامه نویسی شئ گرا با تعریف کلی Polymorphism آشنا شدیم و در این بخش تصمیم داریم به صورت عملی با نحوه پیاده سازی این قابلیت در زبان سی شارپ آشنا شویم.

همانطور که در قسمت مقدمه گفتیم، Polymorphism به معنای قابلیت تعریف مجدد رفتار یک موجودیت در کلاس های فرزند می باشد. Polymorphism در زبان سی شارپ به سه روش قابل پیاده سازی است:

  1. استفاده از متد های virtual و override کردن آنها در کلاس های فرزند
  2. استفاده از رفتارهای abstract در کلاس والد
  3. استفاده از قابلیت interface ها

در این قسمت، حالت اول را بررسی می کنیم و حالت دوم و سوم، یعنی استفاده از متدهای abstract و interface ها را در بخش های بعدی توضیح خواهیم داد.


متدهای virtual


همانطور که گفتیم یکی از روش های پیاده سازی Polymorphism استفاده از متدهای virtual و override کردن آنها در کلاس فرزند است. برای مثال، فرض کنیم کلاس پایه ای داریم با عنوان Shape که در آن رفتاری با نام Draw تعریف کردیم. رفتار Draw وظیفه ترسیم شئ را بر عهده دارد. در این مثال ها، تنها در متدها پیامی را در پنجره کنسول چاپ می کنیم، اما در محیط واقعی هر یک از این متدها وظیفه ترسیم شئ را بر عهده خواهند داشت. همانطور که گفتیم کلاس Shape رفتار Draw را تعریف می کند. این رفتار در بین تمامی اشیاء ای که از کلاس Shape مشتق می شوند مشترک است. در ابتدا کلاس Shape را به صورت زیر تعریف می کنیم:

public class Shape
{
    public void Draw()
    {
        Console.WriteLine("Drawing the shape!");
    }
}

حالا باید کلاس های فرزند را تعریف کنیم. ما سه کلاس به نام های Rectangle، Triangle و Circle که وظیفه ترسیم مستطیل، مثلث و دایره را بر عهده دارند تعریف می کنیم که هر سه از کلاس Shape مشتق شده اند:

public class Rectangle : Shape
{
        
}

public class Triangle : Shape
{
        
}

public class Circle : Shape
{
        
}

هر سه کلاسی که در بالا تعریف کردیم، شامل متد Draw هستند، زیرا این متد در کلاس پایه یعنی Shape تعریف شده است. حال از هر یک، شئ ای ساخته و متد Draw را صدا می زنیم:

var rect = new Rectangle();
var tri = new Triangle();
var circ = new Circle();

rect.Draw();
tri.Draw();
circ.Draw();

Console.ReadKey();

خروجی دستورات بالا به صورت زیر می باشد:

Drawing the shape!
Drawing the shape!
Drawing the shape!

اما خروجی مدنظر ما تولید نشده است. ما می خواهیم هر کلاس رفتار مربوط به خود را داشته باشد. درست است که رفتار Draw در کلاس پایه تعریف شده، اما باید بتوانیم این رفتار را برای کلاس های فرزند تغییر دهیم. برای اینکار باید در کلاس پایه مشخص کنیم که کدم رفتار را می خواهیم تغییر دهیم. برای اینکار، کافیست رفتار مورد نظر را از نوع virtual تعریف کنیم. اعضای virtual به ما این اجازه را می دهند تا در کلاس فرزند مجدد آنها را تعریف کنیم. برای اینکار متد Draw در کلاس Shape را به صورت زیر تغییر می دهیم:

public virtual void Draw()
{
    Console.WriteLine("Drawing the shape!");
}

دقت کنید، کلمه کلیدی virtual قبل از نوع بازگشتی متد نوشته می شود. حالا باید در کلاس فرزند رفتار Draw را مجدداً تعریف کنیم. برای اینکار باید متدی که از نوع virtual تعریف شده است را override کنیم. ابتدا رفتار Draw را برای کلاس Rectangle تغییر می دهیم. کد کلاس Rectangle را به صورت زیر تغییر دهید:

public class Rectangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Drawing rectangle!");
    }
}

حالا با اجرای مجدد کد خروجی به صورت زیر تغییر می کند:

Drawing rectangle!
Drawing the shape!
Drawing the shape!

زمانی که شما داخل کلاس Rectangle شروع به تایپ می کنید، بعد از نوشتن کلمه کلیدی override و زدن کلید space لیستی از متدهایی که قابل override شدن هستند برای شما نمایش داده می شوند:

img1


همچنین در صورتی که ابزار Resharper را نصب کرده باشید، وارد scope کلاس شده و کلید های Alt+Insert را فشار دهید، با اینکار منوی Generate برای شما نمایش داده می شود، از طریق این منو و انتخاب گزینه Overriding members لیستی از تمامی اعضای قابل override شدن به شما نمایش داده می شود:

img2


img3


بعد از انتخاب عضو مورد نظر و فشار دادن کلید Finish متد مورد نظر برای شما override می شود. مهمترین کاربرد این ویژگی، زمانی است که شما تصمیم دارید چندین ویژگی را با هم override کنید. به یک نکته توجه داشته باشید، چه با روش اول متد را override کنید، چه با روش دوم، کدی برای شما به صورت خودکار درج می شود که به صورت زیر است:

public override void Draw()
{
    base.Draw();
}

در قسمت قبل با کلمه کلیدی base آشنا شدید، در کد بالا که به صورت پیش فرض نوشته می شود، با فراخوانی متد Draw از شئ ای که متد داخل آن override شده، نسخه کلاس پایه از رفتار فراخوانی می شود که شما باید بر اساس نیاز خود کد مورد نظر را برای رفتار override شده بنویسید.

کلاس های Triangle و Circle را نیز به صورت زیر تغییر می دهیم:

public class Triangle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Draw triangle!");
    }        
}

public class Circle : Shape
{
    public override void Draw()
    {
        Console.WriteLine("Draw circle!");
    }        
}

بعد از اجرای برنامه، خروجی باید به صورت زیر باشد:

Drawing rectangle!
Drawing triangle!
Drawing circle!

شاید خیلی از دوستان این سوال برایشان پیش بیاید که دلیل اینکار چیست؟ ما که متدها را در هر کلاس نوشتیم، چرا باید از کلاس پایه و override کردن آنها استفاده می کردیم؟ مهمترین خاصیت استفاده از Polymorphism استفاده از کلاس پدر برای کارهاست. برای درک بهتر، فرض کنید میخواهیم آرایه ای از اشیاء داشته باشیم. همانطور که می دانید، ما سه کلاس مختلف داریم و در صورت استفاده نکردن از قابلیت وراثت باید برای هر یک از کلاس ها یک آرایه تعریف کنیم. اما با قابلیت وراثت می توان یک آرایه از نوع کلاس پایه تعریف کرد و اشیاء فرزند را داخل آن قرار داد:

Shape[] shapes = new Shape[5];
shapes[0] = new Circle();
shapes[1] = new Triangle();
shapes[2] = new Circle();
shapes[3] = new Rectangle();
shapes[4] = new Triangle();

foreach (var shape in shapes)
    shape.Draw();

Console.ReadKey();

با اجرای کد بالا خروجی زیر به نمایش داده می شود:

Drawing circle!
Drawing triangle!
Drawing circle!
Drawing rectangle!
Drawing triangle!

با اینکه ما کلاس پایه یعنی Shape را به عنوان نوع آرایه در نظر گرفتیم، اما در هر خانه از آرایه ای شئ ای از نوع فرزندان کلاس Shape قرار دادیم و به دلیل override کردن رفتار Draw در کلاس های مشتق شده، فراخوانی متد Draw بر اساس تعریفی که در کلاس های فرزند داشتیم انجام می شود.

تعریف مجدد یا override کردن تنها محدود به رفتارها یا همان متدها نمی باشد. شما خصوصیات یا Property ها را نیز می توانید از نوع virtual تعریف کنید. برای مثال کلاسی را با نام Human فرض کنید که دارای سه خصوصیت به نام های FirstName و LastName و FullSpecification می باشد:

public class Human
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public string FullSpecification
    {
        get { return FirstName + " " + LastName; }
    }
}

در کلاس بالا، خاصیت FullSpecification نام کامل را بر میگرداند. حالا کلاس فرزندی تعریف می کنیم با نام Employee یا کارمند که از کلاس Human مشتق شده است و خاصیت جدید با نام JobPosition یا موقعیت شغلی به آن اضافه می کنیم:

public class Employee : Human
{
    public string JobPosition { get; set; }
}

در صورتی که شئ ای از روی Employee بسازیم و خاصیت FullSpecification آن را چاپ کنیم، نام و نام خانوداگی او در خروجی چاپ می شود. اما می خواهیم این خاصیت علاوه بر نام کامل، موقعیت شغلی او را نیز در خروجی چاپ کند. برای اینکار کافیست که در کلاس Human خاصیت FullSpecification را به صورت virtual تعریف کرده و در کلاس فرزند مجدد بخش get آن را تعریف کنیم:

public class Human
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public virtual string FullSpecification
    {
        get { return FirstName + " " + LastName; }
    }
}

public class Employee : Human
{
    public string JobPosition { get; set; }

    public override string FullSpecification
    {
        get { return base.FullSpecification + " with job position: " + JobPosition; }
    }
}

در کلاس Employee به بخش get توجه کنید:

get { return base.FullSpecification + " with job position: " + JobPosition; }

در این قسمت، از کلمه کلیدی base برای گرفتن مقدار FullSpecification استفاده شده است. این خاصیت نام کامل را برای ما بر میگرداند و ما به انتهای آن موقعیت شغلی شخص را اضافه می کنیم و بر میگردانیم.

قابلیت Polymorphism در برنامه نویسی شئ گرا نقش بسیار پر رنگی دارد و خیلی جاها از نوشتن کدهای تکراری جلوگیری کرده و حجم کد برنامه شما را به صورت محسوسی کاهش می دهد. در بخش بعدی آموزش زبان سی شارپ، با کلاس ها و متدهای abstract و همچنین کلاس های sealed آشنا می شویم. ITPRO باشید

نویسنده : حسین احمدی
منبع : جزیره برنامه نویسی وب سایت توسینسو
هرگونه نشر و کپی برداری بدون ذکر منبع و نام نویسنده دارای اشکال اخلاقی است
برچسب ها
ردیف عنوان
1 دوره آموزشی .NET Framework و زبان برنامه نویسی سی شارپ - مقدمه
2 آموزش سی شارپ - قسمت اول :: معرفی و بررسی ابزارهای مورد نیاز دوره
3 آموزش زبان سی شارپ - قسمت دوم :: آشنایی با .NET Framework و ساختار آن (بخش اول)
4 آموزش زبان سی شارپ - قسمت دوم :: آشنایی با .NET Framework و ساختار آن (بخش دوم)
5 آموزش زبان سی شارپ - قسمت سوم :: آشنایی اولیه با محیط Visual Studio و نوشتن اولین برنامه
6 آموزش زبان سی شارپ - قسمت چهارم :: آشنایی با ساختار برنامه ها و کامپایلر زبان سی شارپ
7 آموزش زبان سی شارپ - قسمت پنجم :: آشنایی با دستورات کنسول و متغیرها
8 آموزش زبان سی شارپ - قسمت ششم :: نوع های داده اولیه
9 آموزش زبان سی شارپ - قسمت هفتم :: آشنایی با عملگرهای زبان سی شارپ
10 آموزش زبان سی شارپ - قسمت هشتم :: آشنایی با دستورات کنترلی و حلقه ها (بخش اول)
11 آموزش زبان سی شارپ - قسمت هشتم :: آشنایی با دستورات کنترلی و حلقه ها (بخش دوم)
12 آموزش زبان سی شارپ - قسمت هشتم :: آشنایی با دستورات کنترلی و حلقه ها (بخش سوم)
13 آموزش زبان سی شارپ - قسمت هشتم :: آشنایی با دستورات کنترلی و حلقه ها (بخش چهارم)
14 آموزش زبان سی شارپ - قسمت نهم :: آشنایی با آرایه ها و دستور foreach
15 آموزش زبان سی شارپ - قسمت دهم :: آشنایی با متدها در زبان سی شارپ (بخش اول)
16 آموزش زبان سی شارپ - قسمت دهم :: آشنایی با متدها در زبان سی شارپ (بخش دوم)
17 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت یازدهم :: مقدمه ای بر برنامه نویسی شئ گرا
18 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت دوازدهم :: آشنایی با کلاس، اشیاء و فضاهای نام
19 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت سیزدهم :: آشنایی با فیلدها و رفتارها
20 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت چهاردهم :: آشنایی با Property ها
21 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت پانزدهم :: آشنایی با سازنده ها و روش های ایجاد اشیاء
22 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت شانزدهم :: وراثت یا Inheritance
23 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت هفدهم :: آشنایی با مفهوم Polymorphism
24 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت هجدهم:: کلاس های abstract و sealed
25 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت نوزدهم :: سازنده ها در وراثت، کلمه کلیدی protected و فیلدهای readonly
26 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت بیستم :: کلاس های static و partial و Extension Method ها
27 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت بیست و یکم :: Reference Types و Value Types
28 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت بیست و دوم :: آشنایی با کاربرد interface ها
29 آموزش برنامه نویسی شئ گرا در زبان سی شارپ - قسمت بیست و سوم :: آشنایی با مفاهیم Inversion of Control و Dependency Injection
30 آموزش برنامه نویسی شئ گرا در زبان سی شارپ -قسمت بیست و چهارم :: آشنایی با مفهوم Type Casting و انواع Cast ها
31 آموزش برنامه نویسی شئ گرا در زبان سی شارپ -قسمت بیست و پنجم :: آشنایی با operator overloading و تعریف cast ها
32 آموزش برنامه نویسی شئ گرا در زبان سی شارپ -قسمت بیست و ششم :: مفاهیم boxing و unboxing
33 آموزش برنامه نویسی شئ گرا در زبان سی شارپ -قسمت بیست و هفتم :: قابلیت Generics
34 آموزش برنامه نویسی شئ گرا در زبان سی شارپ -قسمت بیست و هشتم :: نکات تکمیلی Generic ها، کلاس List و کلاس Dictionary
35 آموزش زبان سی شارپ -قسمت بیست و نهم (پایانی): استثناء ها (Exceptions) و مدیریت خطاها در سی شارپ
دوره مجموعه کل دوره
مطالب مرتبط

در حال دریافت اطلاعات

نظرات
  • سلم مهندس تنها مرجعی که در اینترنت به دلم نشت برای اموزش سی شار پ اموزش های شماست. سلمان بدرقه
  • ممنونم سلمان جان، امیدوارم این سری آموزشی برای دوستانی که تصمیم به یادگیری زبان برنامه نویسی سی شارپ دارن مفید باشه.
  • عرض ادب و خسته نباشید.
    مبحث وراثت در این اموزش ، خیلی شیوا و قابل فهم بیان شده. سپاسگزار از اشتراک دانسته هاتان. بنده شروع به یادگیری Unity کردم و متوجه شدم مبحث وراثت بسیار در انجا مهم هست. منابع زیادی را مطالعه کردم اما اینجا چیز دیگریست!

برای ارسال نظر ابتدا به سایت وارد شوید