تقييم الموضوع :
  • 0 أصوات - بمعدل 0
  • 1
  • 2
  • 3
  • 4
  • 5
الواجهة IComparable والواجهة IComparer
#1
كاتب الموضوع : Islam Ibrahim

هذا الموضوع يناقش أحد استخدامات مبادئ البرمجة كائنية التوجه.

توضح هذه المقالة خطوة بخطوة استخدام الواجهتين IComparer و IComparable سأقوم بمناقشة هاتين الواجهتين في نفس الموضوع وذلك لسببين اثنين. أولاً أنه كثيراً ما تستخدم هاتين الواجهات معاً ، وعلى الرغم من أنهما متشابهين في الاسم إلا أن لهما أغراضاً مختلفة.

إذا كان لديك مصفوفة من نوع محدد (مثل String أو Integer) وحيث ذلك النوع يدعم بالفعل الواجهة IComparer يمكنك القيام بعملية فرز هذه المصفوفة دون الاستعانة مجدداً بالواجهة IComparer,. وذلك باستدعاء الإجراء Sort بدون تحميل زائد للمعاملات والخاص بالمصفوفة والذي سيؤدي إلى تنفيذ الإجراء الافتراضي لعملية الفرز والممثل بـ IComparer (Comparer.CompareTo) ومع ذلك، إذا كنت ترغب في توفير إمكانية فرز أو مقارنة عناصر المصفوفة بطريقتك الخاصة حسب احتياجاتك, يجب عليك القيام بعملية Implementation (أو "تنفيذ" إن صح التعبير) للواجهة IComparable أو IComparer, مع ملاحظة أنه يمكن الاستغناء عن إحدى الواجهتين فليس ضرورياً أن تنفذهما معاً.

الواجهة IComparable

يتمثل دورا لواجهة IComparable في توفير وسيلة لمقارنة كائنين اثنين من نوع محدد. وهذا ضروري إذا كنت ترغب في توفير ميزة لترتيب الكائنات الخاصة بك. يمكنك اعتبار IComparable أنه هو المسئول عن الكيفية الافتراضية لترتيب الكائنات . على سبيل المثال، إذا كان لديك مصفوفة من النوع Car فعند استدعاء الإجراء Sort سيتم المقارنة بين الكائنات ضمن تلك لمصفوفة حسب السلوك البرمجي الذي تحدده أنت من خلال الواجهة IComparable (مثلا: تاريخ البيع, أو تاريخ التسليم...) وذلك بكتابة الإجراء CompareTo للواجهة IComparable يدوياً كما يلي:


كود :
Private Function CompareTo(ByVal obj As Object) As Integer Implements IComparable.CompareTo
Dim c As car = DirectCast(obj, car)

Return String.Compare(Me.make, c.make)
End Function
تختلف طريقة المقارنة في الإجراء CompareTo استناداً إلى نوع البيانات الذي نتعامل معه , فمثلا في المثال السابق قمنا بمقارنة الخاصية Make من نوع String والخاصة بكائنين من النوع Car لذلك قمنا باستخدام الدالة String.Compare من أجل عملية المقارنة.

الواجهة IComparer

دور IComparer هو توفير آليات إضافية من أجل عملية المقارنة. على سبيل المثال، قد تحتاج إلى توفير إمكانية الفرز تصاعدياً أو تنازلياً لأحد الخصائص أو الحقول الخاصة بفئتك.
استخدام IComparer عملية تتم في خطوتين. أولا، تعلن فئة جديدة تطبّق الواجهة IComparer ، ثم بعد ذلك تنفيذ الإجراء الخاص بالمقارنة:


كود :
Private Class sortYearAscendingHelper
Implements IComparer
Private Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As car = DirectCast(a, car)
Dim c2 As car = DirectCast(b, car)
If c1.year > c2.year Then
Return 1
End If
If c1.year < c2.year Then
Return -1
Else
Return 0
End If
End Function
End Class
لاحظ أن الإجراء IComparer.Compare يقوم بإرجاع القيم 1, 0, أو -1 استناداً إلى ما إذا كانت إحدى القيم أكبر من أو تساوي أو أقل من.... يمكن تغيير عملية الفرز (تصاعدي أو تنازلي) وذلك تبديل كيفية المقارنة في هذا الإجراء.

ملاحظة: يمكن إضافة أكثر من فئة تطبق الواجهة IComparer إلى الفئة الرئيسية Car مثلا فئة تقوم بمقارنة تاريخ التسليم وفئة أخرى لمقارنة تاريخ البيع (على سبيل المثال) وهكذا.... , كما سيتم توضيح ذلك في المثال اللاحق.

الخطوة الثانية هي تعريف دالة داخل الفئة sortYearAscendingHelper تقوم بإرجاع كانن من النوع IComparer الخاص بك.


كود :
Public Shared Function sortYearAscending() As IComparer
Return DirectCast(New sortYearAscendingHelper(), IComparer)
End Function
الكائن الذي ُيعاد من الدالة السابقة سيتم تمريره إلى الإجراء Sort الخاص بالمصفوفة.

سيوضح المثال التالي كيفية استخدام هذه الواجهات. سنقوم بإنشاء فئة ما ونسميها Car وسننفذ الواجهتين IComparer و IComparable. بحيث تحتوي هذه الفئة ( Car) خاصيتين Make و Year. سنجعل الخاصية Make تدعم الفرز من خلال الواجهة IComparable وكذلك الفرز التنازلي من خلال الواجهة IComparer. سنقوم أيضا بجعل الخاصية Year تدعم الفرز التصاعدي والتنازلي من خلال الواجهة IComparer.

أنشئ مشروع جديد بالفيجوال بيسك دوت نت من نوع Console Application.
أضف إلى المشروع االحالي فئة جديدة وقم بتسميتها Car واجعلها تنفذ الواجهة IComparable كما يلي:


كود :
Imports System.Collections
Public Class car
Implements IComparable
End Class
سنضيف الحقول الخاصة بالخاصيتين Make و Year وكذلك منشئ الفئة Constructor, كما يلي:


كود :
Private m_year As Integer
Private m_make As String

Public Sub New(ByVal Make As String, ByVal Year As Integer)
m_make = Make
m_year = Year
End Sub

Public Property Year() As Integer
Get
Return m_year
End Get
Set(ByVal value As Integer)
m_year = value
End Set
End Property

Public Property Make() As String
Get
Return m_make
End Get
Set(ByVal value As String)
m_make = value
End Set
End Property
بعد ذلك نضيف الإجراء CompareTo التالي والذي سيقوم بمقارنة كائنين من النوع Car حسب وفرزهما تنازليا وهو ماستقوم به الدالة String.Compare:


كود :
Private Function CompareTo(ByVal obj As Object) As Integer Implements IComparable.CompareTo
Dim c As car = DirectCast(obj, car)
Return [String].Compare(Me.m_make, c.make)
End Function
انتهينا الآن من الواجهة IComparable وسننتقل للواجهة IComparer:

أضف فئتين جديدتين داخل الفئة Car واحدة مسؤولة عن ترتيب الكائنات من النوع Car في مصفوفة تنازلياُ والأخرى تصاعدياُ حسب الخاصية Year السابقة كما يلي:


كود :
‘ ترتيب التاريخ تصاعدياً
Private Class sortYearAscendingHelper
Implements IComparer
Private Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As car = DirectCast(a, car)
Dim c2 As car = DirectCast(b, car)

If c1.year > c2.year Then
Return 1
End If

If c1.year < c2.year Then
Return -1
Else

Return 0
End If
End Function
End Class

‘ ترتيب التاريخ تنازليا
Private Class sortYearDescendingHelper
Implements IComparer
Private Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As car = DirectCast(a, car)
Dim c2 As car = DirectCast(b, car)

If c1.year < c2.year Then
Return 1
End If

If c1.year > c2.year Then
Return -1
Else

Return 0
End If
End Function
End Class

Private Class sortMakeDescendingHelper
Implements IComparer
Private Function Compare(ByVal a As Object, ByVal b As Object) As Integer Implements IComparer.Compare
Dim c1 As car = DirectCast(a, car)
Dim c2 As car = DirectCast(b, car)
Return [String].Compare(c2.make, c1.make)
End Function
End Class
بعد ذلك سنضيف بعض الدوال الإضافية المساعدة والتي سنحتاجها من أجل تمرير القيم العائدة منها كمعاملات للإجراء Sort والتي على أساسها يتم تحديد كيفية المقارنة:


كود :
Public Shared Function sortYearAscending() As IComparer
Return DirectCast(New sortYearAscendingHelper(), IComparer)
End Function

Public Shared Function sortYearDescending() As IComparer
Return DirectCast(New sortYearDescendingHelper(), IComparer)
End Function

Public Shared Function sortMakeDescending() As IComparer
Return DirectCast(New sortMakeDescendingHelper(), IComparer)
End Function
طبعاً الدوال السابقة تخص الفئات التي تنفذ الواجهة IComparer وهي sortYearDescendingHelper و sortYearAscendingHelper و sortMakeDescendingHelper.

والآن سنقوم بتجربة الفئة Car كما يلي:

تعريف مصفوفة من النوع Car, ثم إضافة مجموعة من الكائنات من النوع Car لها
ثم نقوم بعرض ترتيبها العشوائي, بعد ذلك نقوم بترتيبها حسب الخصائص Make و Year تصاعديا وتنازلياُ كما يلي:

في Module الرئيسي للبرنامج أضف الكود التالي:


كود :
Imports System

Module Module1

Sub Main()
Dim c As car
Dim arrayOfCars() As car = _
{ _
New car("Ford", 1992), _
New car("Fiat", 1988), _
New car("Buick", 1932), _
New car("Ford", 1932), _
New car("Dodge", 1999), _
New car("Honda", 1977) _
}

Dim t As String = vbTab & vbTab
Dim n As String = vbCrLf

Console.WriteLine("Array - Unsorted" & n)
For Each c In arrayOfCars
Console.WriteLine(c.Make & t & c.Year)
Next
Array.Sort(arrayOfCars)
Console.WriteLine(n & "Array - Sorted by Make (Ascending - IComparable)" & n)
For Each c In arrayOfCars
Console.WriteLine(c.Make & t & c.Year)
Next
Array.Sort(arrayOfCars, car.sortYearAscending())
Console.WriteLine(n & "Array - Sorted by Year (Ascending - IComparer)" & n)
For Each c In arrayOfCars
Console.WriteLine(c.Make & t & c.Year)
Next

Array.Sort(arrayOfCars, car.sortMakeDescending())
Console.WriteLine(n & "Array - Sorted by Make (Descending - IComparer)" & n)
For Each c In arrayOfCars
Console.WriteLine(c.Make & t & c.Year)
Next

Array.Sort(arrayOfCars, car.sortYearDescending())
Console.WriteLine(n & "Array - Sorted by Year (Descending - IComparer)" & n)
For Each c In arrayOfCars
Console.WriteLine(c.Make & t & c.Year)
Next

Console.ReadLine()

End Sub
End Module
شغل البرنامج وسيكون الناتج في نافذة الكونسول كما يلي:



كود :
Array - Unsorted

Ford 1992
Fiat 1988
Buick 1932
Ford 1932
Dodge 1999
Honda 1977

Array - Sorted by Make (Ascending - IComparable)

Buick 1932
Dodge 1999
Fiat 1988
Ford 1932
Ford 1992
Honda 1977

Array - Sorted by Year (Ascending - IComparer)

Ford 1932
Buick 1932
Honda 1977
Fiat 1988
Ford 1992
Dodge 1999

Array - Sorted by Make (Descending - IComparer)

Honda 1977
Ford 1932
Ford 1992
Fiat 1988
Dodge 1999
Buick 1932

Array - Sorted by Year (Descending - IComparer)

Dodge 1999
Ford 1992
Fiat 1988
Honda 1977
Buick 1932
Ford 1932
من خلال ما سبق يمكن استنتاج الآتي:

IComparable تستخدم مع الإجراء Sort بدون تمرير معاملات وهي ترتب العناصر افتراضياً حسب الإجراء CompareTo.

عندما نكون بحاجة إلى طرق إضافية للترتيب عندها يصبح تنفيذ الواجهة IComparable غير كافياً لذلك سنحتاج إلى إنشاء فئة جديدة مساعدة تقوم بمقارنة العناصر حسب الحاجة بحيث تنفذ تلك الفئة الواجهة IComparer, وللقيام بترتيب عناصر المصفوفة باستخدام الفئة المساعدة تلك نقوم باستدعاء الإجراء Sort وهو Overloaded ونمرر له المصفوفة ونسخة من الفئة المساعدة.
}}}
تم الشكر بواسطة:


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  موضوع للنقاش- الواجهة IDisposable RaggiTech 2 2,621 05-10-12, 01:20 AM
آخر رد: RaggiTech
  تحقيق الواجهة IEnumerable(Of T) RaggiTech 0 1,836 03-10-12, 07:56 AM
آخر رد: RaggiTech
  إدارة المصادر والواجهة IDisposable RaggiTech 1 2,385 01-10-12, 11:38 PM
آخر رد: RaggiTech

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


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