المشاركات : 1,733
المواضيع 147
الإنتساب : Sep 2012
السمعة :
215
الشكر: 8484
تم شكره 12163 مرات في 1145 مشاركات
29-06-16, 01:43 AM
(آخر تعديل لهذه المشاركة : 30-06-16, 05:00 AM {2} بواسطة الشاكي لله.)
السلام عليكم ورحمة الله وبركاته
في هذا الرد سنوضح الفرق بين الـ Interface والـ Class من ناحية الوراثة ـ
بينما بقية المقارنات مشروحة في الردود تحت بواسطة الاعضاء الكرام ..
احيانا نحتاج الى استعمال مبدأ الوراثة ، ولكن معظمنا لايعرف ماذا يستخدم للوراثة ، هل يستخدم الـ Interface او يستخدم الـ Class ؟
ولكن المقالة التالية ستوضح بشكل قاطع متى يستخدم الـ Class ومتى يستخدم الـ Interface
سؤال / متى استخدم الوراثة من كلاس (Inheritance from Base Class) ومتى استخدم الوراثة من الواجهات البرمجية(Inheritance from Interface) ؟
او ممكن اعادة صياغة السؤال بضمير المتحدث :-
سؤال / انا بحاجة لتطبيق مبدأ الوراثة ، فهل اقوم بانشاء Base Class او اقوم بانشاء Interface ؟
-----------------------------------------------
الجواب :- المفهومان يتشابهان الى حد كبير لدرجة انك احيانا لا تعلم ايهما تستخدم .. لذلك وجدت العلاقة التالية التي تحدد لك بوضوح ايهما يجدر استعماله :-
العلاقة الاولى : Is-a ، عندما تكون لدينا هذه العلاقة بين اثنين Types ، هنا نقوم بانشاء Base Class ونقوم بالاشتقاق منها ((Inheritance from Base Class)
العلاقة الثانية : can-do ـ عندما تكون لدينا هذه العلاقة بين اثنين Types ، هنا نقوم بانشاء واجهة برمجية ونقوم بالاشتقاق منها (Inheritance from Interface)
--
مثال من مكتبات ال.NET ... هناك كلاس اسمه Bitmap ، هذا الكلاس مشتق من الكلاس Image
لماذا قام مصمم اللغة بتعريف Class باسم Image ؟، لماذا لم يقم بتعريف Image كـ Interface ؟
السبب لان العلاقة المستخدمة بين الكلاسين هي Is-a >>
Bitmap Is an Image
وفي نفس الوقت ، الكلاس Bitmap مشتق كذلك من واجهة برمجية تسمى IDisposable وايضا من واجهة اخرى تسمى ICloneable
لماذا قام مصمم اللغة بتعريف Interface باسم IDisposable ، لماذا لم يقم بتعريف IDisposable كـ Class ؟
لان العلاقة المستخدمة هنا can-do >>
Bitmap can do Dispose
Bitmap can do Clone
اذن الشكل العام للكلاس Bitmap سيكون كالتالي :-
PHP كود :
public class Bitmap : Image , IDisposable , ICloneable {
}
--
مثال اخر/ انظر هذا الكود :-
PHP كود :
class Ahmed : Person, IWalk, ISleep, ISwim { }
في الكود السابق هناك كلاس باسم Ahmed وهو يشتق من Base Class المسمى Person ، ويشتق ايضا من ثلاثة Interface
السبب في اشتقاق Ahmed من الكلاس Person
هو وجود علاقة Is-a >>
ِAhemd is a Person
بينما السبب في الاشتقاق من الInterfaces المسميات IWalk و IEat و ISleep
هو وجود العلاقة can-do >>
Ahmed can walk
Ahmed can eat
Ahmed can sleep
لذلك يجب ان تُعرًف Person كـ Class ، لانها تحقق علاقة Is- a
بينما يجب عليك ان تُعرًف IWalk و IEat و ISleep كـ Interface ، لانهم يحققون علاقة can- do
وهذا كود تعريفهم :-
PHP كود :
//base class class Person { }
//interfaces interface IWalk { } interface IEat { } interface ISleep { }
--
الخاتمة :-
دائما عندما تقوم بكتابة اكوادك وعندما تكون بحاجة لاستعمال مبدأ الوراثة ، يجدر بك ان تعرف متى تقوم بانشاء Interface و متى تقوم بانشاء Base Class وذلك باستخدام العلاقتين اعلاه .
تحياتي[/b]
المشاركات : 662
المواضيع 39
الإنتساب : Feb 2014
السمعة :
195
الشكر: 1474
تم شكره 1740 مرات في 622 مشاركات
كلام جميل اخي الشاكي و خصوصا عندما تريد عمل مبدأ الوراثة المتعددة
كما تعلم الوراثة المتعددة غير مدعومة في عملنا على #C
لذلك اتى مبدأ تطبيق الواجهات حل سحري لتلافي القصر Implement Interfaces
مثلا لو كان لدي كلاسين كما يلي
PHP كود :
Class FirstClass { } Class SecondClass { }
فانني لن استطيع تطبيق ما يلي
PHP كود :
class NewClass : FirstClass, SecondClass { }
بينما لو كان لدي واجهتين كما يلي
PHP كود :
interface X { } interface Y { }
يصبح من السهل علي الاستفادة منهما كما يلي
PHP كود :
class NewClass : X, Y { }
كما يمكنني ايضا وراثة الكلاس و تطبيق الواجهة في نفس الوقت كما يلي
PHP كود :
class NewClass : FirstClass, X { }
و بقيت الاشارة الى ان Interface
تحتوي فقط على على طرق و خصائص و متغيرات بدون كود فقط تمهيد لها
و باعادة تطبيقها يمكنك كتابة الاكواد المناسبة لهذه الطرق كما تشاء.
بعكس Class الذي يحتوي على كل شيئ.
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
المشاركات : 1,733
المواضيع 147
الإنتساب : Sep 2012
السمعة :
215
الشكر: 8484
تم شكره 12163 مرات في 1145 مشاركات
29-06-16, 02:33 AM
(آخر تعديل لهذه المشاركة : 29-06-16, 02:33 AM {2} بواسطة الشاكي لله.)
(29-06-16, 02:15 AM)ابو ليلى كتب : ^
جزاك الله خيرا على هذه المداخلة القيمة
هذا الرد بمثابة درس كامل عن الInterface
بارك الله فيك
--
بقي شيئ واحد اعتقد يجب توضيجه للجميع بخصوص الInterface
ماهي الفائدة العملية من الـ Interface ؟
كنت حاب اجاوب على هذا السؤال ، لكن مو وقته حاليا ..
المشاركات : 662
المواضيع 39
الإنتساب : Feb 2014
السمعة :
195
الشكر: 1474
تم شكره 1740 مرات في 622 مشاركات
الفوائد كثيرة اخي و خصوصا اذا كنت من اصحاب الطرق التوسعية
انا استخدمتها في تقنية Plugins لتوظيف طرق جديدة داخل التطبيق
و العملية جدا ممتعة و رهيبة من خلال Interfaces
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
المشاركات : 1,733
المواضيع 147
الإنتساب : Sep 2012
السمعة :
215
الشكر: 8484
تم شكره 12163 مرات في 1145 مشاركات
29-06-16, 03:50 AM
(آخر تعديل لهذه المشاركة : 29-06-16, 04:34 AM {2} بواسطة الشاكي لله.)
^
يامحاسن الصدف ...
انا ايضا تعاملت مع الPlugin بالـ Reflector
ولكن ليس باستعمال الـ Interface بل باستعمال الـ Abstract class (اخت الـ Interface بالرضاعة )
والسبب في ذلك ان الInterface لاتدعم كتابة المتغيرات بداخلها ، وهذا سبب لي مشكلة
مثلا كنت اريد اضافة متغير Name بهذا الشكل
PHP كود :
interface IPlugin { public string Name }
الا اننا نعرف ان الكود اعلاه بيسبب مشكلة ، لان الInterface لاتدعم ذلك
وحتى لو قمت بتحويل Name الى Property سيبب ذلك مشكلة وهو انني سأضطر الى اعادة تعريف للخاصية في الكلاس الجديد (بالعربي ، مااستفدت شيئ )
بالاضافة الى ذلك ، لو طبقنا العلاقتين المذكورتين بالموضوع ، سنجد ان علاقة Is- a هي التي تصلح لموضوع الPlugin
لو عرفت Plugin باسم MyPlugin فيجب ان تستورث من Class لان العلاقة ستصبح >>>
MyPlugin Is a Plugin
MyPlugin can Plugin(لغويا غير ممكنة ، لذلك العلاقة لاتصلح)
اذن العلاقة هي Is- A فيجب الاشتقاق من Class .. ولكن المشكلة بالـ classes العادية ان اكوادها ثابتة ولاتناسب موضوع الPlugin لاننا نحتاج الى Type يمكننا من عمل Re-Implemented لاستعماله كقالب للcasting او لاستعماله في Plugin اخرى ..
ولكن -لحسن الحظ- Abstract class هو المنقذ [/b]
PHP كود :
abstract class PluginBase { public string Name { get; set; } public string Author { get; set; } public abstract void Load(); }
//plugins public class MyPlugin : PluginBase { public MyPlugin() { this.Name = "Sound Plugin v1.0"; this.Author = "Vb4arb"; } public override void Load() { //my staff } } public class BrotherPlugin : PluginBase { public BrotherPlugin() { this.Name = "Video Plugin v1.0"; this.Author = "google"; }
public override void Load() { //brother staff } }
المشاركات : 531
المواضيع 4
الإنتساب : May 2016
السمعة :
55
الشكر: 694
تم شكره 535 مرات في 367 مشاركات
أساتذة اجتمعوا في موضوع........
المشاركات : 2,469
المواضيع 2
الإنتساب : Nov 2014
السمعة :
602
الشكر: 17073
تم شكره 15267 مرات في 2998 مشاركات
اخي الوادي فعلا سبقتني
لو كنت امتلك صلاحية تغيير عنوان الموضوع
لكتبت " لقاء العمالقة و ال Interface "
المشاركات : 1,817
المواضيع 141
الإنتساب : Sep 2013
السمعة :
112
الشكر: 7278
تم شكره 3459 مرات في 585 مشاركات
29-06-16, 03:55 PM
(آخر تعديل لهذه المشاركة : 29-06-16, 04:02 PM {2} بواسطة Sajad.)
السلام عليكم
جزاكم الله خيرا على هذا النقاش الجميل
أحب أن اضيف بعض المعلومات بخصوص الـ interface
لا يمكن انشاء instance من interface
لا يمكن استخدام الـ (Access Specifiers ) محددات الوصول(public, private ) عند تعريف الدوال داخل الـ interface لأنها public by default
PHP كود :
interface IC { public void Print(); // Error }
الصحيح
PHP كود :
interface IC { void Print(); // هذا هو التصريح الصحيح للدالة بدون استخدام محددات الوصول }
لذا عند استخدام الدوال في الـ class سيكون عليك لزاماً أن تعرف الدوال كــ public في الclass وإن لم تفعل ذلك سخبركك المترجم بأن هنالك خطأ
PHP كود :
class A : IC { void Print() // Error { Console.Write("Hello"); } }
الصحيح
PHP كود :
class A : IC { public void Print() { Console.Write("Hello"); } }
يمكن لــ interface أن يرث من interface آخر
في حال تعريف دالة داخل الــ interface سيكون لزاماً عليك استخدامها في الـ class التي يرث من الـ interface
طيب ماذا لو كان لدينا class ورث من اثنين interface وكلا الـ interface يحتويان نفس الدالة حتى لو كانت الدوال لها وظائف مختلفة؟ بالشكل التالي:
PHP كود :
interface IC { void Print(); }
interface IB { void Print(); }
لذا يتم حل المشكلة بالشكل التالي:
PHP كود :
class A : IB, IC { void IC.Print() { Console.Write("Hello C"); Console.ReadKey(); }
void IB.Print() { Console.Write("Hello B"); Console.ReadKey(); } }
في هذه الحالة الدوال تعرف على أنها private by default
طيب كيف سيكون استدعاء الدوال؟
الجواب: سنستخدم هنا Explicit interface بالشكل التالي:
لأن الدوال private فلا يمكن الوصول اليها إلا باستخدام Explicit interface
PHP كود :
private static void Main() { var a = new A(); ((IC) a).Print(); ((IB) a).Print(); }
تحياتي لكم
المشاركات : 2,469
المواضيع 2
الإنتساب : Nov 2014
السمعة :
602
الشكر: 17073
تم شكره 15267 مرات في 2998 مشاركات
اتلذذ بقراءة مثل هذه المقالات والردود الراقية
ما شاء الله عليكم
واتمنى من مشرفين القسم تثبيت المقال
المشاركات : 1,733
المواضيع 147
الإنتساب : Sep 2012
السمعة :
215
الشكر: 8484
تم شكره 12163 مرات في 1145 مشاركات
شكرا للاخ سجاد على المداخلة القيمة ، وشكرا للاخ امير الزبيدي على المشاركة والتشجيع
يبدو ان مواضيع الـ OOP تعجبكم
اذن اليوم مقالة اخرى ان شاء الله
|