تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
الدرس الحادي والعشرون - الوراثة Inheritance
#1
كاتب الموضوع : أحمد جمال


بسم الله الرحمن الرحيم .
السلام عليكم ورحمة الله وبركاته .

ذكرنا في درس سابق ان OOP لها ثلاث عناصر اساسية ، قمنا بشرح المفهوم الأول Encapsulation في دروس سابقة ، درسنا اليوم مخصص لشرح الوراثة Inheritance فيما نؤجل شرح مفهوم ال Polymorphism إلى درس لاحق .


والآن سنبدأ بعمل مثال نتابع معه العمل ، لنفترض المثال السابق الذي شرحناه الخاص بالعربة :

C#:


كود :
class Car
{
private string carName;
private int carModel;
public Car(string carName, int carNumber)
{
this.carNme=carName;
this.carNumber=carNumber;
}
public Car()
{
carName="Unknown";
carNumber=0;
}
}
VB.net:


كود :
Class Car

Private carName As String
Private carModel As Integer
Public Sub New(ByVal carName As String, ByVal carNumber As Integer)
Me.carNme = carName
Me.carNumber = carNumber
End Sub
Public Sub New()
carName = "Unknown"
carNumber = 0
End Sub

End Class
سنبدأ بهذا المثال البسيط ، ونتابع العمل على تطويره وتحسينه خلال مراحل هذا الدرس .
}}}
تم الشكر بواسطة:
#2
تعريف علاقة is-a :

كما ذكرنا في الدرس السابع عشر ، فإن العلاقة قد تكون is-a وقد تكون has-a ، سنحاول الآن شرح النوع الأول من العلاقات والذي يعني ان الكلاس المشتق هو من نوع الكلاس الرئيسي ، سنفترض سيارة BMW :

C#:

كود :
class BMW: Car
{
}
VB.net:


كود :
Class BMW
Inherits Car

End Class
هكذا نستطيع ان نقول ان الكلاس الابن BMW يحتوي على نفس خصائص الكلاس الأب Car ونفس دواله وطرقه ال public فقط ، ولكن لنفترض اننا في الكلاس الابن نحاول الوصول المباشر إلى الخاصية carName فلن نتمكن من ذلك ، هذا المثال يوضح هذه النقطة :

C#:


كود :
BMW ahmedcar=new BMW();
ahmedcar.carName="anyname";
VB.net:


كود :
Dim ahmedcar As New BMW()
ahmedcar.carName = "anyname"
حتى لو قمنا بتعريف بعض الدوال داخل الكلاس المشتق بحيث تستطيع الوصول إلى هذه الخاصية ، لنفترض اننا اعدنا صياغة الكلاس BMW ليكون بالشكل التالي :

C#:


كود :
class BMW: Car
{
public changeCarName(string value)
{
carName=value;
}
}
VB.net:


كود :
Class BMW
Inherits Car

Public Sub New(ByVal value As String)
carName = value
End Sub

End Class
للاسف لن يكون هذا صحيحاً تماماً ، حيث انك بالرجوع إلى درس معرفات الوصول ستكشتف ان معرف الوصول private لا يمكن الوصول له من الكلاس المشتق ، من اجل هذا نستخدم معرف الوصول protected حيث انه يشبه ال private في كونه لا يمكن الوصول المباشر له من خلال ال object ، لكنه في المقابل يمكن الوصول إليه من داخل الكلاس المشتق ، لو افترضنا مثال الكلاس Car بالشكل التالي :

C#:

كود :
class Car
{
protected string carName;
protected int carModel;
}
VB.net:

كود :
Class Car
Protected carName As String
Protected carModel As Integer
End Class
في هذه الحالة يمكننا تعريف دالة داخل الكلاس المشتق BMW تقوم بقراءة هذه المتغيرات ، لذا سوف يكون الكود التالي صحيحاً :

C#:

كود :
class BMW: Car
{
public changeCarName(string value)
{
carName=value;
}
}
VB.net:

كود :
Class BMW
Inherits Car

Public Sub New(ByVal value As String)
carName = value
End Sub

End Class
}}}
تم الشكر بواسطة:
#3
الكلمة المحجوزة sealed :

يعني استخدام هذه الكلمة ان هذا الكلاس لا يمكن الاشتقاق منه ، يتم ذلك بالشكل التالي :

C#:

كود :
sealed class Car
{

}
VB.net:


كود :
NotInheritable Class Car

End Class
}}}
تم الشكر بواسطة:
#4
الوراثة المتعددة :

لا توفر لغة السي شارب او ال VB.net مبدأ الوراثة المتعددة ، في حين تطبقه فقط manged c++ ، معنى كلمة الوراثة المتعددة ان بامكان كلاس ما ان يشتق من اكثر من كلاس ، لنفترض لدينا كلاس شاحنة وكلاس سيارة ، في حالة دعم لغة ما للوراثة المتعددة فإننا نستطيع عمل نوع جديد يحتوي على خصائص الشاحنة والسيارة العادية ، ولكن هذا ما لا توفره كل من السي شارب او ال VB.net .

وكبديل لذلك ، تقدم اللغتان دعم لعمل Implementation لاكثر من interface ، وهو ما سنتعرف عليه حينما نصل إلى هذا الجزء .

أما لماذا لم تقدم مايكروسوفت دعم الوراثة المتعددة في C# و VB.net ، إليك هذا الرابط :
http://blogs.msdn.com/csharpfaq/archive/2004/03/07/85562.aspx
}}}
تم الشكر بواسطة:
#5
التعديل في الكلاس المشتق :

كما رأينا في الدروس السابقة ، يمكننا التعديل مباشرة على خصائص وطرق وأحداث ودوال الكلاس الجديد ، في المثال السابق قمنا باضافة دالة تسمح لنا بتغيير الاسم ، يمكننا اضافة خاصية جديدة للكلاس BMW تحتوي على عدد أجهزة التلفزيون داخل السيارة كميزة اضافية في السيارات من نوع BMW ، وهكذا ...

يمكننا عمل كلاس آخر لعربة فيراري ، في هذه الحالة يمكننا اضافة عدد الفتحات الجانبية للمحرك . لكن لو احتجنا في مرحلة الى تعريف خاصية maxSpeed لجميع السيارات فيكفي اضافتها في الكلاس الاساسي Car وستجدها موجودة تلقائياً في الكلاسات الأبناء جميعاً .

من هنا نستطيع ان نلاحظ ان واحدة من الفوائد الرئيسية لعملية الوراثة هي وضع قاعدة عامة للعناصر المتشابهة ، وعمل نسخ لاضافة نقاط الاختلاف فقط بدلاً من اعادة تكرار كل منها عدة مرات ، ربما لن تجد الفرق كبيراً في المثال السابق حيث اننا نعمل مع 3 او 4 خصائص فقط ، ولكن في مثال حقيقي مع عدة اوامر للتعامل مع المستخدم وللحفظ في قاعدة البيانات والطباعة والعرض والعمليات الحسابية ستستطيع ان تدرك الفارق بين استخدام مفهوم الوراثة وعدمه .
}}}
تم الشكر بواسطة:
#6
العلاقة من نوع has-a :

كما اوضحنا في اول درسنا فهذا هو النوع الثاني من العلاقات بين الفئات المختلفة ، هذا النوع يعني ان الكلاس يحتوي على كلاس آخر ، لو افترضنا مثال كلاس العجلات بالشكل التالي :

C#:

كود :
class Tires
{
int TiresType;
int TiresSize;
}
VB.net:


كود :
Class Tires


Private TiresType As Integer

Private TiresSize As Integer

End Class
نعرف يقينا ان الاطارات ليست من نوع سيارة tire is not a car ولكنها جزء من السيارة car has a tire ، لذا يمكننا تعريف كلاس السيارة بالشكل التالي :

C#:


كود :
class Car
{
Tires carTires=new Tires();
}
VB.net:


كود :
Class Car


Private carTires As New Tires()

End Class
لا تنس ان بامكانك تعريفها كـ private او protected وعمل خاصية لها من اجل القراءة والكتابة إليها .
}}}
تم الشكر بواسطة:
#7
ال Casting :

يقصد بال Casting عموماً هو التحويل من نوع إلى آخر .

والآن سنحاول تطبيق نفس المفاهيم على ال Classes ، الطريقة الأولى للتحويل هي استخدام (cast) العادية ، مثلاً لو قمنا بتعريف سيارة BMW :

c#:

كود :
BMW ahmedCar=new BMW();
vb.net:

كود :
Dim ahmedCar As New BMW()
وقمنا بارسال المتغير إلى دالة تقوم باستقبال BMW فسوف تعمل بصورة صحيحة ، ايضاً لو قمنا بارسالها إلى دالة تستقبل Car فسيكون هذا صحيحا لإن كل BMW هي في الحقيقة Car ، بينما العملية العكسية ليست صحيحة .

النقطة الثانية لو قمنا بتعريف BMW بالصورة التالية :

C#:

كود :
Car ahmedCar=new BMW();
vb.net:

كود :
Dim ahmedCar As Car = New BMW()
هذا الموضوع صحيح فعلاً وهو ما يدعى باسم implicit cast ، والآن يمكن ارسال المتغير مباشرة إلى تلك الدالة التي تستقبل Car .

لنفترض مثالاً آخر قمنا فيه بتعريف BMW بالشكل التالي :

C#:

كود :
Object ahmedCar=new BMW();
vb.net:

كود :
Dim ahmedCar As Object = New BMW()
هذا صحيح ايضاً لإن كل كلاس هو Object ايضاً ، لكن لو قمنا بارسال المتغير إلى الدالة التي تستقبل Car فسوف تظهر رسالة خطا ، لذا نقوم بعمل cast بأحد الاشكال التالية :

c#:

كود :
functionname((Car)ahmedCar);
functionname((BMW)ahmedCar);
vb.net:

كود :
functionname(DirectCast(ahmedCar, Car))
functionname(DirectCast(ahmedCar, BMW))
}}}
تم الشكر بواسطة:
#8
الكلمة المحجوزة is :

تقوم هذه الكلمة باختبار فيما إذا كان الطرف الاول هو من الطرف الثاني ، مثال :

c#:


كود :
if (ahmedCar is BMW)
vb.net:


كود :
If TypeOf ahmedCar Is BMW Then
تفيدك هذه الكلمة في حالة وجود عدة متغيرات من عدة انوع مشتقة من نفس الفئة ، ونريد ان نعرف فيما إذا كانت من نوع BMW او فيراري مثلاً .
}}}
تم الشكر بواسطة:
#9
Visual Studio Class Diagram

يوفر لك الفيجوال ستوديو ابتداء من الاصدار 2005 اداة لعمل ال Class Diagram ، هذا مثال عليها :


يمكنك اضافتها من new - class diagram ، ومن ثم العمل عليها مباشرة ، او عرض الكلاسات التي لديك ، يمكنك انشاء العلاقات المختلفة في هذا ال mode .
}}}
تم الشكر بواسطة:



التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم