يعد اسلوب البرمجة الكانئية افضل اسلوب برمجي تطبقه في معظم اللغات الحديثة والقوية وخصوصا لغات الدوت نت سواء كانت VB.Net او C# ، وعندما تطبق هذا الاسلوب فمن الاكيد بانك ستقوم ببناء فئات Classes وستحتوي بداخلها على اعضاء Members كـ Properties,Function,Subs وغيرها ، ثم تستخدم هذه الفئات في أي جزء رئيسي من الرنامج بإنشاء كائن جديد منها ثم اسناد القيم والخصائص إليه من خلال المشيد Constructor في حالة وجوده او من خلال الخصائص القابلة للكتابة Writable Properties او لاشيء من هذا !
لاحقا وبعد ان تكتب الاكواد داخل الأعضاء الخاصة بفئتك التي انشاتها للتو واللحظة ، فإنك قد تتساءل حول عملية قنص الاستثناءات Exceptions ، فماذا لو حدث استثناء معين او خطاء وقت التنفيذ في الكود ؟ هذا ما سنناقشه هنا .
لنفترض انك قد قمت بعمل فئة بالإسم MyData والتي تمثل بيانات شخصيه معينه يتم اسنادها لها ،كالخصائص التالية مثلا : FirstName,FamilyName,Age ، بحيث صارت كالتالي :
|
Public Class MyData Dim _FirstName As String Public Property FirstName() As String Get Return _FirstName End Get Set(ByVal value As String) _FirstName = value End Set End Property
Dim _FamilyName As String Public Property FamilyName() As String Get Return _FamilyName End Get Set(ByVal value As String) _FamilyName = value End Set End Property
Dim _Age As Byte Public Property Age() Get Return _Age End Get Set(ByVal value) _Age = value End Set End Property
End Class |
ثم طلبت منك ان تضيف لهذه الفئة طريقة Method تقوم بكتابة البيانات الى ملف – وذلك بإضافتها الى بيانات اخرى موجودة سابقا- لتكتب الاسم الاول والعائلة والعمر ، ولنفترض – واقول نفترض- انك كتبت الكود التالي بالضبط ( بما فيه من اخطاء فادحة ! ) :
|
Public Sub WriteDataToFile(ByVal FileName As String) Dim FileContent As String FileContent = “الإسم الأول : ” & Me.FirstName & ” العائلة : ” & Me.FamilyName & ” العمر ” & Me.Age
My.Computer.FileSystem.WriteAllText(FileName, FileContent, True)
End Sub |
الآن لو قمنا بإنشاء كائن جديد من هذه الفئة واعطيناه قيما لخصائصه وطلبنا من الكائن ان يتكرم علينا بتنفيذ الطريقة WriteDataToFile واعطيناه الوسيط المناسب كالتالي :
|
Module Module1
Sub Main()
Dim Mohammed As New MyData Mohammed.FirstName = “Mohammed” Mohammed.FamilyName = “AL-Nabhani” Mohammed.Age = 20
Mohammed.WriteDataToFile(“C:\Users\Personals\Documents\MyData.txt”)
Console.ReadLine()
End Sub
End Module |
ثم قمنا بتجربة البرنامج ، لكن مهلا هناك استثناء وارد بنسبه كبيرة جدا وهو ان الملف MyData غير موجود ! قد تفكر بان عملية التحقق من وجود الملف اولا افضل وانا اتفق معك في ذلك تماما ، لكن ما هي سيناريوهات العملية القادمة ؟ اذا لم يجد الملف ماذا يفعل البرنامج ؟
في حالتي لا اريد انشاء ملف لانني اريد ان اضيف البيانات الى الملف MyData لا أن أققوم بإنشاءه في حالة عدم وجودة ، لذلك فإننا نرغب الآن بإعلام المستخدم بأن الملف غير موجود واجزم انك تتفق معي الان في ذلك ، لكن السؤال كيف سنخبر المستخدم بذلك ؟ ان كنت ستقول لنكتب سطرا مثل التالي في الطريقة المعنية :
|
Public Sub WriteDataToFile(ByVal FileName As String) Dim FileContent As String FileContent = “الإسم الأول : ” & Me.FirstName & ” العائلة : ” & Me.FamilyName & ” العمر ” & Me.Age
If My.Computer.FileSystem.FileExists(FileName) = True Then My.Computer.FileSystem.WriteAllText(FileName, FileContent, True) Else Console.Write(“الملف غير موجود”) End If
End Sub |
فسأقول لك ان الطريقة السابقة خاطئة تماما ، صحيح انها ستعطينا الناتج النهائي المطلوب كما قد تشتهيه ، ولكن في في اسلوب البرمجة الكائنيه ذلك خطأ ، فالمفترض ان الفئة التي انشاناها لا تعرض شيء على الشاشة بدون اذن الطريقة Main ، وافرض او اننا اردنا استخدام هذه الفئة في مشروع من نوع WIndowsApplication بدل ConsoleApplication فماذا ستفعل ؟ الادهى لو قمت بترجمه الفئة الى ملف Dll فكيف ستعرف نوع المشروع الحالي ؟ حتى لو عرفت من خلال الكود فهل يعجبك ان تكتب جملة شرطية للتأكد من نوع المشروع ثم اظهار رسالة الخطأ بالطريقة الخاصة بكل واحد ؟
اتمنى انك اقتنعت بذلك ، اما الحل فسيكون بتعديل الطريقة WriteDataToFile لتكون دالة Function بدل Sub وجعلها تعود بقيمة معينه ، طيب فكر معي ، ما هو النوع Type الخاص بهذه الدالة function والتي ستعيده ؟ هل ستعيد Boolean لنعرف ان حدث خطأ ام لا ؟ ام تعيد String في كل مرة ام أي نوع ؟ طيب لنفكر في كل واحدة على حده :
- 1- النوع Boolean : فكرة جيدة ، لجعل الدالة تعيد قيمة True ان تم تنفيذها كما يجب ، و False في الحالة المعاكسه ولكن يعيبها عدم اعادتها لرسالة الخطأ ، ففي حالة امكانية حدوث اكثر من خطأ واحد فهناك ستواجه مشكلة حول أي رسالة خطأ ستعرض او أي اجراء ستنفذ .
- 2- النوع String : طريقة جيدة نوعا ما ، لكن لو اردت كتابة دالة تعيد نوع معينا مثلا تقرأ ملفا معينا وتعيد الاسم الاول فكيف ستعرف ان ما اعادته هو الاسم الاول او رسالة الخطأ ؟
لا تقل لي لنضع Field ( حقل ) عام على مستوى المشروع بمثابته متغير من النوع Boolean يعرف اذا حدث خطا ام لا فهذه الطريقة تنتهك OOP من كل النواحي !
طيب ما الحل اذا ؟
الحل يتم بعمل نوع جديد خاص بنا لمثل هذه الحالات ، وهو عمل فئة Class تحمل خاصية تخبرنا ان حدث خطا او لا ، وتعطينا ايضا نص رسالة الخطأ او حتى كائن الـ Error بأكمله او أي شيء من هذا القبيل … كما قد نطورها اكثر لتحمل قيمة ما تود ارجاعه كما في الحالة الثانية اعلاه ، وهو الحل الذي سأتبعه في هذا النطاق مع انه قد يوجد حلول افضل ولكن ذلك يعتمد على الحالات التي تواجهها في برامجك .
الفئة الجديدة والتي سنعول عليها معرفة حدوث خطأ وحمل قيمة ناتج عملياتنا اسميتها ExecutionCondition وستحمل الخصائص التالية :
- HasErrors : وهي خاصية للقراءة فقط ReadOnly ومن النوع Boolean
- ErrorMessage : وهي خاصية للقراءة فقط ايضا ومن النوع Strign
- Value : وهي خاصية اختيارية لك ، وهي من النوع Object .
بالنسبة للطرق فقد وضعت اجرائين فقط :
- SetErrorMessage : وهو الذي نستخدمه في اعطاء الخاصية ErrorMessage قيمتها وبناءا عليه تتحدد قمية الخاصية HasErrors .
- Reset : يعيد الكائن الى حالته الاساسية أي بدون خطأ مع عدم المساس بقيمة الكائن المتمثل في الخاصية Value .
لن اقوم بشرح كل شيء في هذه الفئة ، فهي واضحة وضوح الشمس لكل من لديه اساسيات ولو بسيطة في OOP :
|
”’ <summary> ”’ This class is used to return an object with value and error message when error occur ”’ </summary> ”’ <remarks></remarks> Public Class ExecutionCondition #Region “Properties” Dim _HasErrors As Boolean ”’ <summary> ”’ Determines if the assosiated process has an errors while executing it ”’ </summary> ”’ <value></value> ”’ <returns></returns> ”’ <remarks></remarks> Public ReadOnly Property HasErrors() As Boolean Get If Me._HasErrors = True Then Me._ErrorMessage = “” Return _HasErrors End Get End Property
Dim _ErrorMessage As String ”’ <summary> ”’ Gets the error message if the assisiated process has an erors while executing ”’ </summary> ”’ <value></value> ”’ <returns></returns> ”’ <remarks></remarks> Public ReadOnly Property ErrorMessage() As String Get Return _ErrorMessage End Get
End Property
Dim _Value As Object ”’ <summary> ”’ Represents the value of the ibject, it could be any type . ”’ </summary> ”’ <value></value> ”’ <returns></returns> ”’ <remarks></remarks> Public Property Value() As Object Get Return _Value End Get Set(ByVal value As Object) _Value = value End Set End Property #End Region
#Region “Methods”
Public Sub New()
End Sub ”’ <summary> ”’ Sets the Error Message ”’ </summary> ”’ <param name=”Message”>”the message of the error that will be presented in Error Message property</param> ”’ <remarks></remarks> Public Sub SetErrorMessage(ByVal Message As String) _ErrorMessage = Message _HasErrors = True End Sub ”’ <summary> ”’ resets the object so no errors are contained ”’ </summary> ”’ <remarks></remarks> Public Sub Reset() Me._HasErrors = False
End Sub #End Region End Class |
الآن لنقم بعمل مثال عملي جديد لنجرب استخدام هذه الفئة ، اما بخصوص مثالنا السابق والفئة MyData فاعتبره تمرينا لك لحل مشكلتنا الأساسية !
في الوحدة النمطية Module1 التي تحتوي على الطريقة Main – الجزء الاساسي من البرنامج بطبيعة الحال – فقد قمت باضافة الدالة التالية فيها :
|
Function WriteOnTheScreen() As ExecutionCondition Dim mExCn As New ExecutionCondition
Try Console.WriteLine(5 / 1) Console.ReadLine()
mExCn.Reset()
Catch ex As Exception mExCn.SetErrorMessage(ex.Message) End Try
Return mExCn End Function |
وفي الطريقة Main كتبت الكود التالي :
|
Sub Main() ‘لنجرب تنفيذ الدالة ‘WriteOnTheScreen If WriteOnTheScreen.HasErrors = True Then Console.WriteLine(WriteOnTheScreen.ErrorMessage) End If Console.ReadLine() End Sub |
بعد تشغيل البرنامج سيظهر كل شيء على ما يرام هذه المرة وسيطبع 5 ، لنجرب الآن تعديل الطريقة WriteOnTheScreen ولنجعل القسمة مبنية على صفر وهذا خطأ رياضي فادح جدا :
|
Function WriteOnTheScreen() As ExecutionCondition Dim mExCn As New ExecutionCondition
Try
Dim x As Integer = 5 Dim y As Integer = 0 Dim z As Integer = x / y Console.WriteLine(z) Console.ReadLine()
mExCn.Reset()
Catch ex As Exception mExCn.SetErrorMessage(ex.Message) End Try
Return mExCn End Function
|
الآن قم بتنفيذ البرنامج ولاحظ ماسيحدث ، سيطبع نص رسالة الخطأ مهما يكن نوع الخطأ الذي حدث ، سواء القسمة على صفر او أي خطأ آخر وتأكد من كلامي جيدا !
ختاما ارجو انني قد وفقت في لفت الانتباء الى مسألة التعامل مع الاخطاء في الكائنات المستقلة واذا وجد هنا أي خطأ فأرجو تنبيهي عليه وجل من لا يسهو .
أحدث التعليقات