آموزش برنامه نویسی

آموزش سی شارپ

آموزش سی شارپ

پربیننده ترین مطالب
پیوندهای روزانه

همانطور که در بخش قبل گفتیم وراثت یکی از اصلی ترین مباحث برنامه نویسی شئ گرا می باشد. در بخش قبلی با شیوه ارث بری از کلاس ها آشنا شدیم. یکی از مفاهیمی که در برنامه نویسی شئ گرا خیلی کاربرد دارد و وابسته به مفهوم وراثت است، چند ریختی یا 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 آشنا می شویم.

منبع:programming.itpro.ir
  • متین تیماسی ، مبین خسروی و عمران جودکی

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی