TAHA
03-11-2010, 08:48 PM
.wysiwyg { BACKGROUND: #f5f5ff; FONT: 10pt tahoma,tahoma,tahoma; COLOR: #000000 } P { MARGIN: 0px } .inlineimg { VERTICAL-ALIGN: middle } مقدمهای بر برنامه نویسی شیءگرا
برنامه نویسی در محیط .NET بر پایه اشیاء انجام میگیرد. اشیا طرحهایی برنامهپذیرند که میتوانند نمونهایی از بستههای از دادهای مرتبط و دستورات باشند. اشیاء طرحهای کامل و خاصی برای دیگر اعضای محیط برنامه هستند، بدون این که جزییات کارهای درونی خود شیئ مطرح شود. اشیاء از یک قالب به نام کلاس ساخته میشوند. کلاسهای کتابخانهای پایهای .NET یک سری کلاسهایی برای درست کردن اشیاء در برنامههایتان آماده کردهاند. همچنین شما میتوانید کلاسهای اختصاصی خودتان را نیز ساخته و استفاده کنید. در این مقاله شما با مقدمات برنامه نویسی شیئ گرا آشنا میشوید.
اشیاء، اعضا و تجرد (Abstraction)
یک شیئ (Object) یک طرح برنامهپذیر است که چیزهایی را نشان میدهد. در دنیای واقعی، ماشین، دوچرخه، کامپیوتر و… شیئ هستند. هر کدام از این اشیاء یک سری اعمال و خصوصیات دارند. در برنامه شما، یک شیئ شاید یک فرم یا یک کنترل مانند یک دکمه (Button) یا یک Database Connection یا هر چیز دیگری باشد. هر شیئ یک واحد عملیاتی کامل است، و شامل همه دادهای مورد نیازش و دارای همه اعمالی که برای آن ساخته شده است میباشد.
کلاسها (Classes)
کلاسها قالبهایی برای اشیاء هستند. کلاسها را میتوان، “طرحهای اولیه” برای اشیاء فرض کرد. آنها تمام عضوهای یک شیئ را تعیین، و رفتارهای آن را نیز تعریف میکنند. وقتی که یک کلاس مقداردهی شد، یک نمونه درون حافظهای از آن کلاس ساخته میشود. این نمونه شیئ نامیده میشود. برای نمونه سازی از کلاس از کلمه کلیدی New استفاده میشود.
‘ Declares a variable of the Widget type
Dim myWidget As Widget
‘ Instantiates a new Widget object and assigns it to the myWidget variable
myWidget = New Widget()
وقتی یک نمونه از یک کلاس ساخته میشود، یک کپی از نمونه داده بوسیله آن کلاسی که در حافظه ساخته شده تعریف میشود و به مرجع متغییر داده میشود. هر نمونه از کلاس مستقل از دیگر نمونه هاست و میتواند یک طرح جداگانه برنامه پذیر باشد. درهر لحظه، محدودیتی برای تعداد کپی های یک کلاس (که قبلا تعریف شده) وجود ندارد. برای مقایسه، در جهان واقعی، اگر ماشین یک شیئ باشد، کلاس یک طرح برای ماشین است. یک طرح میتواند برای هر تعداد ماشین مورد استفاده قرار گیرد و تغییرات بر روی یک ماشین، تاثیری بر دیگر ماشینها نمیگذارد.
اشیاء و اعضاء (Members)
اشیاء ترکیبی از عضوها هستند. اعضا، تشکیل شده از خصوصیات (Properties)، فیلدها، متدها و رویدادها (Events) و هر چیزی که اطلاعات و اعمالی داشته باشد. فیلدها و خصوصیات، اعضای دادهای هر شیئ هستند. متدها اعمالی هستند که شیئ میتواند انجام دهد و رویدادها اطلاعاتی هستند که زمانیکه اتفاقی در برنامه میافتد یک شیئ به اشیاء دیگر میفرستد یا از آنها دریافت میکند.
در مثال واقعیمان، شیئ ماشین، فیلدها و خصوصیاتی مانند “رنگ”، “مدل”، “سال تولید” دارد. این اطلاعات وضعیت شیئ ماشین را توصیف میکنند. شیئ ماشین میتواند متدهایی مانند “دور زدن” و “تعویض دنده” داشته باشد. متدها رفتاری که شیئ میتواند اجرا کند را نشان میدهند. ماشین شاید رویداد EngineOverheating از طرف شیئ “موتورش” را داشته باشد، یا وقتی با شیئ “درخت” تعامل میکند، شاید رویداد “تصادف” برای آن اتفاق بیفتد.
کپسوله سازی (Encapsulation)
کپسوله سازی روشی است که یک شیئ را مستقل از اینترفیسش پیاده سازی کنیم. یک برنامه با یک شیئ بواسطه اینترفیسش تعامل میکند، که شامل خصوصیات عمومی و متدهایش است. تا زمانی که این اینترفیس ثابت باقی میماند، برنامه میتواند به تعامل با کامپوننت ادامه دهد؛ حتی اگر پیاده سازی اینترفیس بین دو نسخه کاملا” بازنویسی شده باشد.
اشیاء فقط از طریق متدها و خصوصیات عمومیشان با دیگر شیئها تعامل میکنند. دادههای داخلی یک شیئ، نباید در اینترفیس قرار بگیرد. بنابراین فیلدها بهندرت Public تعریف میشوند.
به مثال ماشینمان برگردیم: اگر شیئ ماشین با شیئ راننده تعامل کند، اینترفیس ماشین شاید شامل متدهای “حرکت به جلو”، “حرکت به عقب” و “توقف” باشد. این همه اطلاعاتی است که راننده برای تعامل با ماشین نیاز دارد. ماشین شاید شامل شیئ “موتور” نیز باشد، اما راننده نیازی به شناخت شیئ موتور ندارد. همه اطلاعاتی که راننده درباره این متدها دارد این است که میتوانند فراخوانی شوند و مقادیر ویژهای نیز را برمیگردانند. بنابراین اگر شیئ موتور تغییری کند، تا زمانیکه اینترفیس به درستی به کار خود ادامه میدهد این امر تفاوتی برای راننده ایجاد نمی کند.
چند شکلی (Polymorphism)
چند شکلی توانایی کلاسهای متفاوت، در پیاده سازیهای مختلف از اینترفیسهای عمومی مشابه است. به عبارت دیگر، چندشکلی به متدها و خصوصیات یک شیئ اجازه میدهد، بدون توجه به چگونگی پیاده سازی اعضای آنها، فراخوانی شوند. برای مثال شیئ Driver میتواند بوسیله اینترفیس عمومی ICar با شیئ Car تعامل کند. اگر شیئ دیگری مانند شیئ Truck یا شیئ SportCar اینترفیس عمومی مشابهی را داشته باشند، شیئ Driver میتواند با آنها بدون توجه به پیاده سازی خاص آن اینترفیس تعامل کند. در اینجا دو راه اصلی برای تامین چندشکلی وجود دارد:
چندشکلی اینترفیسی (Interface Polymorphism)
چندشکلی وراثتی (Inheritance Polymorphism)
چندشکلی اینترفیسی (Interface Polymorphism)
اینترفیس یک قرارداد برای رفتار است. در واقع اینترفیس، اعضای یک کلاس را تعیین میکند، اما توضیحاتی درباره پیاده سازی جزییات آن نمیدهد. یک شیئ میتواند اینترفیسهای زیاد و متفاوتی را پیاده سازی کند و کلاسهای متفاوت زیادی میتوانند یک اینترفیس مشابه را پیاده سازی کنند. همه اشیایی که اینترفیس مشابهی را پیاده سازی میکنند میتوانند با دیگر اشیاء درون اینترفیس تعامل کنند. به عنوان مثال شیئ Car مثال قبل شاید اینترفیس IDrivable را پیاده سازی کند (به عنوان قرار داد، اینترفیسها با I شروع میشوند)، که متدهای GoForward, GoBackward و Stop را تعیین میکند. کلاسهای دیگر مانند Truck ،Forklift یا Boat میتوانند این اینترفیس را پیاده سازی کنند و بنابراین میتوانند با شیئ Driver تعامل داشته باشند. شیئ Driver از پیاده سازی انیترفیسی که با آن تعامل دارد بی اطلاع است.
چندشکلی وراثتی (Inheritance Polymorphism)
وراثت به شما امکان میدهد که اعمال یک کلاس از پیش تعریف شده را در یک کلاس جدید با هم ترکیب کنید و اعضای متفاوت مورد نیاز را در آن پیاده سازی کنید. کلاسی که از کلاس دیگری ارث می برد “مشتق” آن کلاس، یا “وارث” آن کلاس نامیده میشود. یک کلاس میتواند مستقیما” فقط از یک کلاس ارث ببرد، که آن کلاس که از آن ارث می برد را کلاس پایه (Base Class) مینامند. کلاس جدید اعضای مشابهی با کلاس پایه دارد، و اعضای اضافی که مورد نیاز باشند میتوانند افزوده شوند. به علاوه، در کلاس جدید بوسیله overriding پیاده سازی کلاس پایه، اعضای پایه میتوانند تغییر کنند. کلاسهای وارث، همه ویژگیهای کلاس پایه را نگه میدارند و میتوانند با دیگر اشیاءیی که نمونههایی از کلاس پایه هستند تعامل کنند. به عنوان مثال، اگر کلاس Car یک کلاس پایه باشد، SportsCar میتواند یک کلاس مشتق شده از آن باشد. کلاس SportsCar نیز میتواند کلاس پایهای برای کلاس مشتق شده دیگری مثل کلاس ConvertibleSportsCar باشد. هر کلاس مشتق شده جدید، ممکن است اعضای جدید را پیاده سازی کند، اما اعمالی که در کلاس اولیه Car تعریف شدهاست همچنان باقی میمانند.
Overloading اعضاء
Overloading به شما امکان میدهد که چندین عضو با نام مشابه درست کنید. هر عضوی که همنام با عضو دیگری است، باید امضای متفاوتی داشته باشد. Overloading بیشتر در بین متدها متداول است.
شاید شما بخواهید متدی درست کنید که بتواند مجموعههای متفاوتی از پارامترها را بپذیرد:
Public Sub Display(ByVal DisplayValue As Integer)
‘ Implementation Omitted
End Sub
این متد کاملا” پذیرفتنی است. اما فرض کنیم که میخواهید به کلاینت اجازه دهید اگر نیاز بود پارامتر Duration را انتخاب کند. یا اینکه شاید بخواهید متد بتواند مقادیر Integer یا String را به عنوان پارامتر DisplayValue بپذیرد. گرچه در VB.NET اجازه دارید پارامترهای اختیاری داشته باشید اما بهترین راه Overloading است. Overloadها متدهای چندگانه هستند. متدهای Overload شده باید امضای متفاوتی داشته باشند. اما نیاز ندارند مقدار بازگشتی و نوع و یا سطح دسترسی مشابهی داشته باشد. وقتی یک متد Overload شده صدا زده میشود، CLR نوع آرگومانهای تحویل داده شده در فراخوانی متد را بررسی میکند. سپس لیست آرگومانها را با فراخوانیها و امضاهای Overloadهای موجود تطابق میدهد. اگر هیچ Overloadای با نوع آرگومانها تناسب نداشته باشد، یک خطا اعلام میشود.
ساختن متدهای Overload
شما میتوانید یک متد Overload شده را از راهی شبیه آنچه دیگر متدها را میسازید، درست کنید: بوسیله توصیف متد با یک نام، یک سطح دسترسی، یک نوع بازگشتی، و یک لیست آرگومان. یک متد Overload شده باید نامی شبیه متدی موجود اما با امضایی متفاوتی با آن داشته باشد. سطح دسترسی و نوع بازگشتی میتواند مشابه و یا متفاوت باشد. مثال زیر یک متد Overload شده را نشان میدهد.
‘ This example demonstrates an overloaded method.
Public Sub DisplayMessage(ByVal i As Integer)
MessageBox.Show(i.ToString())
End Sub
‘ This method has the same name as the previous method, but is
‘ distinguishable by signature
Public Sub DisplayMessage(ByVal s As String)
MessageBox.Show(s)
End Sub
وقتی یک متد با نام DisplayMessage فراخوانی میشود، CLR نوع آرگومانهای تحویل داده شده را مشخص میکند. اگر یک String باشد، متدی که String میگیرد، صدا زده میشود و اگر یک Integer باشد، متدی که Integer میگیرد فراخوانی میشود.
اینترفیسها
اینترفیس یک قرارداد است. هر شیئ که پیاده سازی میشود، برای تامین پیاده سازی اعضای تعیین شده در آن اینترفیس یک ضمانت نامه اینترفیس میگیرد. اگر یک شیئ نیاز به تعامل با اینترفیسی داشته باشد، میتواند با هر شیئ که آن اینترفیس را پیاده سازی میکند تعامل داشته باشد. یک اینترفیس فقط اعضایی را تعریف میکند که بوسیله شیئ که بعدا پیاده سازی خواهد شد ساخته میشود. تعریف اینترفیس هیچ اطلاعاتی درباره پیاده سازی اعضاء جز پارامترهایی که میگیرند و نوع مقادیری که آنها برخواهند گرداند، نمیدهد و پیاده سازی اینترفیسها کاملا به پیاده سازی کلاس واگذار میشود.
بنابراین این امکان دارد که در اشیاء مختلف پیاده سازیهای مختلفی از اعضای مشابه داشته باشیم. به عنوان مثال، اینترفیسی به نام IShape که یک متد CalculateArea تعریف میکند. کلاس Circle این اینترفیس را برای محاسبه مساحت خود، به طریق متفاوتی با کلاس Square پیاده سازی میکند. هر چند که یک شیئ که نیاز به تعامل با IShapeدارد میتواند متد CalculateArea را فراخوانی کند و هر دوی Circle یا Square نتایج درستی میدهند.
تعریف اینترفیسها
اینترفیسها با کلمه کلیدی Interface تعریف میشوند.
Public Interface IDrivable
End Interface
این اعلان اینترفیس IDrivable را تعریف میکند اما هیچ عضوی برای آن تعریف نمیکند. متدهای یک عضو باید با امضای متد تعریف شود، اما بدون بدون تعریف سطح دسترسی مثل Public و Private. سطح دسترسی یک اینترفیسس سطح دسترسی اعضای آن اینترفیس را نیز تعیین میکند. پس اگر یک اینترفیس Public داشته باشید، همه اعضایش هم باید Public باشند. مثال زیر نشان میدهد که چطور متدها را به اینترفیس اضافه کنید:
Public Interface IDrivable
Sub GoForward(ByVal Speed As Integer)
Sub Halt()
Function DistanceTraveled() As Integer
End Interface
همچنین شما میتوانید خصوصیات را نیز به اینترفیسها اضافه کنید. خصوصیت باید ReadOnly یا WriteOnly تعریف شوند. مثال زیر را ببینید:
Public Interface IDrivable
‘ This defines a read-only property.
ReadOnly Property FuelLevel() As Integer
End Interface
اگرچه شما میتوانید خصوصیات را در اینترفیسها تعریف کنید، اما نمیتوانید فیلدها را در آنها تعریف کنید. این شرط تضمین میکند که کلاسهایی که از طریق اینترفیسها تعامل دارند به دادهای درونی یک شیئ دسترسی نداشته باشند.
اینترفیسها همچنین میتوانند رویدادها را تعریف کنند:
Public Interface IDrivable
Event OutOfFuel(ByVal sender As Object, e As System.EventArgs)
End Interface
چند شکلی با اینترفیسها (Polymorphism with Interfaces)
هر شیئ که یک اینترفیس خاص را پیاده سازی میکند، میتواند با هر یک از اشیاء دیگری که به آن اینترفیس نیاز دارند، تعامل کند.
Public Sub GoSomewhere(ByVal v As IDrivable)
‘ Implementation omitted
End Sub
این متد نیاز به یک پیاده سازی از اینترفیس IDrivable دارد. هر شیئ که این اینترفیس را پیاده سازی میکند میتواند به عنوان یک پارامتر به این متد پاس داده شود. وقتی یک شیئ توسط اینترفیسش تعامل میکند، فقط اعضاء آن اینترفیس در دسترس هستند.
شما همچنین میتوانید به طور ضمنی اشیایی که اینترفیس خاصی را پیاده سازی میکنند درست کنید. (توجه کنید در این مثال Truck باید IDrivable را پیاده سازی کند)
Dim myTruck As New Truck()
Dim myVehicle As IDrivable
‘ Casts myTruck to the IDrivable interface
myVehicle = CType(myTruck, IDrivable)
پیاده سازی اینترفیسها
در VB.Net اینترفیسها بوسیله کلاسها و ساختارها (Structures) با کلمه کلیدی Implements پیاده سازی میشوند:
Public Class Truck
Implements IDrivable
‘ Additional implementation code omitted
End Class
کلاسها میتوانند چندین اینترفیس را پیاده سازی کنند. اگر بخواهید کلاسی تعریف کنید که چندین اینترفیس را پیاده سازی کند، میتوانید نام اینترفیسها را با کاما از هم جدا کنید. مثال زیر را ببینید:
Public Class Truck
Implements IDrivable, IFuelBurning, ICargoCarrying
‘ Additional implementation code omitted
End Class
وقتی یک کلاس یا ساختاری یک اینترفیس را پیاده سازی میکند، شما باید برای هر یک از اعضای آن اینترفیس پیاده سازی جداگانهای انجام دهید. اگر اینترفیسهای چندگانه پیاده سازی شوند، باید یک پیاده سازی برای هر عضو هر اینترفیسی انجام دهید.
پیاده سازی اعضای اینترفیسها
در VB.NET، یک عضو کلاس با کلمه کلیدی Implements یک عضو اینترفیس را پیاده سازی میکند. عضو کلاسی که عضو اینترفیس را پیاده سازی میکند باید امضایی مشابه آن چه در اینترفیس تعریف شده، داشته باشد. اما نیاز نیست که سطح دسترسی مشابهی با آن داشته باشد. مثال بعد نشان میدهد چگونه یک عضو اینترفیس تعریف میشود.
Public Interface IDrivable
Sub GoForward(ByVal Speed As Integer)
End Interface
Public Class Truck
Implements IDrivable
Public Sub GoForward(ByVal Speed As Integer)
Implements IDrivable.GoForward
‘ Implementation omitted
End Sub
End Class
عضو کلاسی که یک عضو اینترفیس را پیاده سازی میکند مجبور نیست که نامی مشابه نام عضو اینترفیس داشته باشد. مثال بعد یک پیاده سازی کاملا معتبر متد GoForward از اینترفیس IDrivable را نشان میدهد:
Public Sub Move(ByVal Speed As Integer)
Implements IDrivable.GoForward
‘ Implementation omitted
End Sub
هر فراخوانی متد GoForward از اینترفیس IDrivable در مثال قبل، متد Move را از کلاس Truck اجرا میکند. همچنین شما میتوانید سطح دسترسی متفاوتی را برای متد کلاسی که متد اینترفیس را پیاده سازی میکند در نظر بگیرید. به عنوان مثال میتوانید متد Public اینترفیس را متد Private کلاس پیاده سازی کنید. اگر این روش را انجام دهید، وقتی که دسترسی درون اینترفیس است متد Public میشود، اما وقتی دسترسی به عنوان عضوی از کلاس است Private میماند.
برنامه نویسی در محیط .NET بر پایه اشیاء انجام میگیرد. اشیا طرحهایی برنامهپذیرند که میتوانند نمونهایی از بستههای از دادهای مرتبط و دستورات باشند. اشیاء طرحهای کامل و خاصی برای دیگر اعضای محیط برنامه هستند، بدون این که جزییات کارهای درونی خود شیئ مطرح شود. اشیاء از یک قالب به نام کلاس ساخته میشوند. کلاسهای کتابخانهای پایهای .NET یک سری کلاسهایی برای درست کردن اشیاء در برنامههایتان آماده کردهاند. همچنین شما میتوانید کلاسهای اختصاصی خودتان را نیز ساخته و استفاده کنید. در این مقاله شما با مقدمات برنامه نویسی شیئ گرا آشنا میشوید.
اشیاء، اعضا و تجرد (Abstraction)
یک شیئ (Object) یک طرح برنامهپذیر است که چیزهایی را نشان میدهد. در دنیای واقعی، ماشین، دوچرخه، کامپیوتر و… شیئ هستند. هر کدام از این اشیاء یک سری اعمال و خصوصیات دارند. در برنامه شما، یک شیئ شاید یک فرم یا یک کنترل مانند یک دکمه (Button) یا یک Database Connection یا هر چیز دیگری باشد. هر شیئ یک واحد عملیاتی کامل است، و شامل همه دادهای مورد نیازش و دارای همه اعمالی که برای آن ساخته شده است میباشد.
کلاسها (Classes)
کلاسها قالبهایی برای اشیاء هستند. کلاسها را میتوان، “طرحهای اولیه” برای اشیاء فرض کرد. آنها تمام عضوهای یک شیئ را تعیین، و رفتارهای آن را نیز تعریف میکنند. وقتی که یک کلاس مقداردهی شد، یک نمونه درون حافظهای از آن کلاس ساخته میشود. این نمونه شیئ نامیده میشود. برای نمونه سازی از کلاس از کلمه کلیدی New استفاده میشود.
‘ Declares a variable of the Widget type
Dim myWidget As Widget
‘ Instantiates a new Widget object and assigns it to the myWidget variable
myWidget = New Widget()
وقتی یک نمونه از یک کلاس ساخته میشود، یک کپی از نمونه داده بوسیله آن کلاسی که در حافظه ساخته شده تعریف میشود و به مرجع متغییر داده میشود. هر نمونه از کلاس مستقل از دیگر نمونه هاست و میتواند یک طرح جداگانه برنامه پذیر باشد. درهر لحظه، محدودیتی برای تعداد کپی های یک کلاس (که قبلا تعریف شده) وجود ندارد. برای مقایسه، در جهان واقعی، اگر ماشین یک شیئ باشد، کلاس یک طرح برای ماشین است. یک طرح میتواند برای هر تعداد ماشین مورد استفاده قرار گیرد و تغییرات بر روی یک ماشین، تاثیری بر دیگر ماشینها نمیگذارد.
اشیاء و اعضاء (Members)
اشیاء ترکیبی از عضوها هستند. اعضا، تشکیل شده از خصوصیات (Properties)، فیلدها، متدها و رویدادها (Events) و هر چیزی که اطلاعات و اعمالی داشته باشد. فیلدها و خصوصیات، اعضای دادهای هر شیئ هستند. متدها اعمالی هستند که شیئ میتواند انجام دهد و رویدادها اطلاعاتی هستند که زمانیکه اتفاقی در برنامه میافتد یک شیئ به اشیاء دیگر میفرستد یا از آنها دریافت میکند.
در مثال واقعیمان، شیئ ماشین، فیلدها و خصوصیاتی مانند “رنگ”، “مدل”، “سال تولید” دارد. این اطلاعات وضعیت شیئ ماشین را توصیف میکنند. شیئ ماشین میتواند متدهایی مانند “دور زدن” و “تعویض دنده” داشته باشد. متدها رفتاری که شیئ میتواند اجرا کند را نشان میدهند. ماشین شاید رویداد EngineOverheating از طرف شیئ “موتورش” را داشته باشد، یا وقتی با شیئ “درخت” تعامل میکند، شاید رویداد “تصادف” برای آن اتفاق بیفتد.
کپسوله سازی (Encapsulation)
کپسوله سازی روشی است که یک شیئ را مستقل از اینترفیسش پیاده سازی کنیم. یک برنامه با یک شیئ بواسطه اینترفیسش تعامل میکند، که شامل خصوصیات عمومی و متدهایش است. تا زمانی که این اینترفیس ثابت باقی میماند، برنامه میتواند به تعامل با کامپوننت ادامه دهد؛ حتی اگر پیاده سازی اینترفیس بین دو نسخه کاملا” بازنویسی شده باشد.
اشیاء فقط از طریق متدها و خصوصیات عمومیشان با دیگر شیئها تعامل میکنند. دادههای داخلی یک شیئ، نباید در اینترفیس قرار بگیرد. بنابراین فیلدها بهندرت Public تعریف میشوند.
به مثال ماشینمان برگردیم: اگر شیئ ماشین با شیئ راننده تعامل کند، اینترفیس ماشین شاید شامل متدهای “حرکت به جلو”، “حرکت به عقب” و “توقف” باشد. این همه اطلاعاتی است که راننده برای تعامل با ماشین نیاز دارد. ماشین شاید شامل شیئ “موتور” نیز باشد، اما راننده نیازی به شناخت شیئ موتور ندارد. همه اطلاعاتی که راننده درباره این متدها دارد این است که میتوانند فراخوانی شوند و مقادیر ویژهای نیز را برمیگردانند. بنابراین اگر شیئ موتور تغییری کند، تا زمانیکه اینترفیس به درستی به کار خود ادامه میدهد این امر تفاوتی برای راننده ایجاد نمی کند.
چند شکلی (Polymorphism)
چند شکلی توانایی کلاسهای متفاوت، در پیاده سازیهای مختلف از اینترفیسهای عمومی مشابه است. به عبارت دیگر، چندشکلی به متدها و خصوصیات یک شیئ اجازه میدهد، بدون توجه به چگونگی پیاده سازی اعضای آنها، فراخوانی شوند. برای مثال شیئ Driver میتواند بوسیله اینترفیس عمومی ICar با شیئ Car تعامل کند. اگر شیئ دیگری مانند شیئ Truck یا شیئ SportCar اینترفیس عمومی مشابهی را داشته باشند، شیئ Driver میتواند با آنها بدون توجه به پیاده سازی خاص آن اینترفیس تعامل کند. در اینجا دو راه اصلی برای تامین چندشکلی وجود دارد:
چندشکلی اینترفیسی (Interface Polymorphism)
چندشکلی وراثتی (Inheritance Polymorphism)
چندشکلی اینترفیسی (Interface Polymorphism)
اینترفیس یک قرارداد برای رفتار است. در واقع اینترفیس، اعضای یک کلاس را تعیین میکند، اما توضیحاتی درباره پیاده سازی جزییات آن نمیدهد. یک شیئ میتواند اینترفیسهای زیاد و متفاوتی را پیاده سازی کند و کلاسهای متفاوت زیادی میتوانند یک اینترفیس مشابه را پیاده سازی کنند. همه اشیایی که اینترفیس مشابهی را پیاده سازی میکنند میتوانند با دیگر اشیاء درون اینترفیس تعامل کنند. به عنوان مثال شیئ Car مثال قبل شاید اینترفیس IDrivable را پیاده سازی کند (به عنوان قرار داد، اینترفیسها با I شروع میشوند)، که متدهای GoForward, GoBackward و Stop را تعیین میکند. کلاسهای دیگر مانند Truck ،Forklift یا Boat میتوانند این اینترفیس را پیاده سازی کنند و بنابراین میتوانند با شیئ Driver تعامل داشته باشند. شیئ Driver از پیاده سازی انیترفیسی که با آن تعامل دارد بی اطلاع است.
چندشکلی وراثتی (Inheritance Polymorphism)
وراثت به شما امکان میدهد که اعمال یک کلاس از پیش تعریف شده را در یک کلاس جدید با هم ترکیب کنید و اعضای متفاوت مورد نیاز را در آن پیاده سازی کنید. کلاسی که از کلاس دیگری ارث می برد “مشتق” آن کلاس، یا “وارث” آن کلاس نامیده میشود. یک کلاس میتواند مستقیما” فقط از یک کلاس ارث ببرد، که آن کلاس که از آن ارث می برد را کلاس پایه (Base Class) مینامند. کلاس جدید اعضای مشابهی با کلاس پایه دارد، و اعضای اضافی که مورد نیاز باشند میتوانند افزوده شوند. به علاوه، در کلاس جدید بوسیله overriding پیاده سازی کلاس پایه، اعضای پایه میتوانند تغییر کنند. کلاسهای وارث، همه ویژگیهای کلاس پایه را نگه میدارند و میتوانند با دیگر اشیاءیی که نمونههایی از کلاس پایه هستند تعامل کنند. به عنوان مثال، اگر کلاس Car یک کلاس پایه باشد، SportsCar میتواند یک کلاس مشتق شده از آن باشد. کلاس SportsCar نیز میتواند کلاس پایهای برای کلاس مشتق شده دیگری مثل کلاس ConvertibleSportsCar باشد. هر کلاس مشتق شده جدید، ممکن است اعضای جدید را پیاده سازی کند، اما اعمالی که در کلاس اولیه Car تعریف شدهاست همچنان باقی میمانند.
Overloading اعضاء
Overloading به شما امکان میدهد که چندین عضو با نام مشابه درست کنید. هر عضوی که همنام با عضو دیگری است، باید امضای متفاوتی داشته باشد. Overloading بیشتر در بین متدها متداول است.
شاید شما بخواهید متدی درست کنید که بتواند مجموعههای متفاوتی از پارامترها را بپذیرد:
Public Sub Display(ByVal DisplayValue As Integer)
‘ Implementation Omitted
End Sub
این متد کاملا” پذیرفتنی است. اما فرض کنیم که میخواهید به کلاینت اجازه دهید اگر نیاز بود پارامتر Duration را انتخاب کند. یا اینکه شاید بخواهید متد بتواند مقادیر Integer یا String را به عنوان پارامتر DisplayValue بپذیرد. گرچه در VB.NET اجازه دارید پارامترهای اختیاری داشته باشید اما بهترین راه Overloading است. Overloadها متدهای چندگانه هستند. متدهای Overload شده باید امضای متفاوتی داشته باشند. اما نیاز ندارند مقدار بازگشتی و نوع و یا سطح دسترسی مشابهی داشته باشد. وقتی یک متد Overload شده صدا زده میشود، CLR نوع آرگومانهای تحویل داده شده در فراخوانی متد را بررسی میکند. سپس لیست آرگومانها را با فراخوانیها و امضاهای Overloadهای موجود تطابق میدهد. اگر هیچ Overloadای با نوع آرگومانها تناسب نداشته باشد، یک خطا اعلام میشود.
ساختن متدهای Overload
شما میتوانید یک متد Overload شده را از راهی شبیه آنچه دیگر متدها را میسازید، درست کنید: بوسیله توصیف متد با یک نام، یک سطح دسترسی، یک نوع بازگشتی، و یک لیست آرگومان. یک متد Overload شده باید نامی شبیه متدی موجود اما با امضایی متفاوتی با آن داشته باشد. سطح دسترسی و نوع بازگشتی میتواند مشابه و یا متفاوت باشد. مثال زیر یک متد Overload شده را نشان میدهد.
‘ This example demonstrates an overloaded method.
Public Sub DisplayMessage(ByVal i As Integer)
MessageBox.Show(i.ToString())
End Sub
‘ This method has the same name as the previous method, but is
‘ distinguishable by signature
Public Sub DisplayMessage(ByVal s As String)
MessageBox.Show(s)
End Sub
وقتی یک متد با نام DisplayMessage فراخوانی میشود، CLR نوع آرگومانهای تحویل داده شده را مشخص میکند. اگر یک String باشد، متدی که String میگیرد، صدا زده میشود و اگر یک Integer باشد، متدی که Integer میگیرد فراخوانی میشود.
اینترفیسها
اینترفیس یک قرارداد است. هر شیئ که پیاده سازی میشود، برای تامین پیاده سازی اعضای تعیین شده در آن اینترفیس یک ضمانت نامه اینترفیس میگیرد. اگر یک شیئ نیاز به تعامل با اینترفیسی داشته باشد، میتواند با هر شیئ که آن اینترفیس را پیاده سازی میکند تعامل داشته باشد. یک اینترفیس فقط اعضایی را تعریف میکند که بوسیله شیئ که بعدا پیاده سازی خواهد شد ساخته میشود. تعریف اینترفیس هیچ اطلاعاتی درباره پیاده سازی اعضاء جز پارامترهایی که میگیرند و نوع مقادیری که آنها برخواهند گرداند، نمیدهد و پیاده سازی اینترفیسها کاملا به پیاده سازی کلاس واگذار میشود.
بنابراین این امکان دارد که در اشیاء مختلف پیاده سازیهای مختلفی از اعضای مشابه داشته باشیم. به عنوان مثال، اینترفیسی به نام IShape که یک متد CalculateArea تعریف میکند. کلاس Circle این اینترفیس را برای محاسبه مساحت خود، به طریق متفاوتی با کلاس Square پیاده سازی میکند. هر چند که یک شیئ که نیاز به تعامل با IShapeدارد میتواند متد CalculateArea را فراخوانی کند و هر دوی Circle یا Square نتایج درستی میدهند.
تعریف اینترفیسها
اینترفیسها با کلمه کلیدی Interface تعریف میشوند.
Public Interface IDrivable
End Interface
این اعلان اینترفیس IDrivable را تعریف میکند اما هیچ عضوی برای آن تعریف نمیکند. متدهای یک عضو باید با امضای متد تعریف شود، اما بدون بدون تعریف سطح دسترسی مثل Public و Private. سطح دسترسی یک اینترفیسس سطح دسترسی اعضای آن اینترفیس را نیز تعیین میکند. پس اگر یک اینترفیس Public داشته باشید، همه اعضایش هم باید Public باشند. مثال زیر نشان میدهد که چطور متدها را به اینترفیس اضافه کنید:
Public Interface IDrivable
Sub GoForward(ByVal Speed As Integer)
Sub Halt()
Function DistanceTraveled() As Integer
End Interface
همچنین شما میتوانید خصوصیات را نیز به اینترفیسها اضافه کنید. خصوصیت باید ReadOnly یا WriteOnly تعریف شوند. مثال زیر را ببینید:
Public Interface IDrivable
‘ This defines a read-only property.
ReadOnly Property FuelLevel() As Integer
End Interface
اگرچه شما میتوانید خصوصیات را در اینترفیسها تعریف کنید، اما نمیتوانید فیلدها را در آنها تعریف کنید. این شرط تضمین میکند که کلاسهایی که از طریق اینترفیسها تعامل دارند به دادهای درونی یک شیئ دسترسی نداشته باشند.
اینترفیسها همچنین میتوانند رویدادها را تعریف کنند:
Public Interface IDrivable
Event OutOfFuel(ByVal sender As Object, e As System.EventArgs)
End Interface
چند شکلی با اینترفیسها (Polymorphism with Interfaces)
هر شیئ که یک اینترفیس خاص را پیاده سازی میکند، میتواند با هر یک از اشیاء دیگری که به آن اینترفیس نیاز دارند، تعامل کند.
Public Sub GoSomewhere(ByVal v As IDrivable)
‘ Implementation omitted
End Sub
این متد نیاز به یک پیاده سازی از اینترفیس IDrivable دارد. هر شیئ که این اینترفیس را پیاده سازی میکند میتواند به عنوان یک پارامتر به این متد پاس داده شود. وقتی یک شیئ توسط اینترفیسش تعامل میکند، فقط اعضاء آن اینترفیس در دسترس هستند.
شما همچنین میتوانید به طور ضمنی اشیایی که اینترفیس خاصی را پیاده سازی میکنند درست کنید. (توجه کنید در این مثال Truck باید IDrivable را پیاده سازی کند)
Dim myTruck As New Truck()
Dim myVehicle As IDrivable
‘ Casts myTruck to the IDrivable interface
myVehicle = CType(myTruck, IDrivable)
پیاده سازی اینترفیسها
در VB.Net اینترفیسها بوسیله کلاسها و ساختارها (Structures) با کلمه کلیدی Implements پیاده سازی میشوند:
Public Class Truck
Implements IDrivable
‘ Additional implementation code omitted
End Class
کلاسها میتوانند چندین اینترفیس را پیاده سازی کنند. اگر بخواهید کلاسی تعریف کنید که چندین اینترفیس را پیاده سازی کند، میتوانید نام اینترفیسها را با کاما از هم جدا کنید. مثال زیر را ببینید:
Public Class Truck
Implements IDrivable, IFuelBurning, ICargoCarrying
‘ Additional implementation code omitted
End Class
وقتی یک کلاس یا ساختاری یک اینترفیس را پیاده سازی میکند، شما باید برای هر یک از اعضای آن اینترفیس پیاده سازی جداگانهای انجام دهید. اگر اینترفیسهای چندگانه پیاده سازی شوند، باید یک پیاده سازی برای هر عضو هر اینترفیسی انجام دهید.
پیاده سازی اعضای اینترفیسها
در VB.NET، یک عضو کلاس با کلمه کلیدی Implements یک عضو اینترفیس را پیاده سازی میکند. عضو کلاسی که عضو اینترفیس را پیاده سازی میکند باید امضایی مشابه آن چه در اینترفیس تعریف شده، داشته باشد. اما نیاز نیست که سطح دسترسی مشابهی با آن داشته باشد. مثال بعد نشان میدهد چگونه یک عضو اینترفیس تعریف میشود.
Public Interface IDrivable
Sub GoForward(ByVal Speed As Integer)
End Interface
Public Class Truck
Implements IDrivable
Public Sub GoForward(ByVal Speed As Integer)
Implements IDrivable.GoForward
‘ Implementation omitted
End Sub
End Class
عضو کلاسی که یک عضو اینترفیس را پیاده سازی میکند مجبور نیست که نامی مشابه نام عضو اینترفیس داشته باشد. مثال بعد یک پیاده سازی کاملا معتبر متد GoForward از اینترفیس IDrivable را نشان میدهد:
Public Sub Move(ByVal Speed As Integer)
Implements IDrivable.GoForward
‘ Implementation omitted
End Sub
هر فراخوانی متد GoForward از اینترفیس IDrivable در مثال قبل، متد Move را از کلاس Truck اجرا میکند. همچنین شما میتوانید سطح دسترسی متفاوتی را برای متد کلاسی که متد اینترفیس را پیاده سازی میکند در نظر بگیرید. به عنوان مثال میتوانید متد Public اینترفیس را متد Private کلاس پیاده سازی کنید. اگر این روش را انجام دهید، وقتی که دسترسی درون اینترفیس است متد Public میشود، اما وقتی دسترسی به عنوان عضوی از کلاس است Private میماند.