تقييم الموضوع :
  • 1 أصوات - بمعدل 5
  • 1
  • 2
  • 3
  • 4
  • 5
[نقاش] الفرق بين الـ Interface , Abstract Class , Base Class , Sealed Class
#1
السلام عليكم ورحمة الله وبركاته




في هذا الرد سنوضح الفرق بين الـ 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 PersonIWalkISleepISwim
   
{
   





في الكود السابق هناك كلاس باسم 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]
الرد }}}
#2
كلام جميل اخي الشاكي و خصوصا عندما تريد عمل مبدأ الوراثة المتعددة 
كما تعلم الوراثة المتعددة غير مدعومة في عملنا على #C 

لذلك اتى مبدأ تطبيق الواجهات حل سحري لتلافي القصر  Implement Interfaces



مثلا لو كان لدي كلاسين كما يلي


PHP كود :
Class FirstClass { }
 
   Class SecondClass { } 

فانني لن استطيع تطبيق ما يلي
PHP كود :
class NewClass FirstClassSecondClass  { } 
بينما لو كان لدي واجهتين كما يلي
PHP كود :
interface { }
    interface 
{ } 


يصبح من السهل علي الاستفادة منهما كما يلي

PHP كود :
class NewClass X{ } 

كما يمكنني ايضا وراثة الكلاس و تطبيق الواجهة في نفس الوقت كما يلي
PHP كود :
class NewClass FirstClass{ } 


و بقيت الاشارة الى ان  Interface    



تحتوي فقط على على طرق و خصائص و متغيرات بدون كود فقط تمهيد لها

و باعادة تطبيقها يمكنك كتابة الاكواد المناسبة لهذه الطرق كما تشاء.

بعكس Class الذي يحتوي على كل شيئ.
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
#3
(29-06-16, 02:15 AM)ابو ليلى كتب : ^

جزاك الله خيرا على هذه المداخلة القيمة

هذا الرد بمثابة درس كامل عن الInterface Big Grin

بارك الله فيك


--


بقي شيئ واحد اعتقد يجب توضيجه للجميع بخصوص الInterface
ماهي الفائدة العملية من الـ Interface ؟


كنت حاب اجاوب على هذا السؤال ، لكن مو وقته حاليا Undecided ..
الرد }}}
تم الشكر بواسطة: Amir_Alzubidy , ابو ليلى , الوادي
#4
الفوائد كثيرة اخي و خصوصا اذا كنت من اصحاب الطرق التوسعية  Big Grin
انا استخدمتها في تقنية Plugins لتوظيف طرق جديدة داخل التطبيق
و العملية جدا ممتعة و رهيبة من خلال Interfaces
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
#5
^
يامحاسن الصدف ...

انا ايضا تعاملت مع الPlugin بالـ Reflector
ولكن ليس باستعمال الـ Interface بل باستعمال الـ Abstract class (اخت الـ Interface بالرضاعة Big Grin)

والسبب في ذلك ان الInterface لاتدعم كتابة المتغيرات بداخلها ، وهذا سبب لي مشكلة
مثلا كنت اريد اضافة متغير Name بهذا الشكل

PHP كود :
   interface IPlugin
   
{
       public string Name 
   



الا اننا نعرف ان الكود اعلاه بيسبب مشكلة ، لان الInterface لاتدعم ذلك
وحتى لو قمت بتحويل Name الى Property سيبب ذلك مشكلة وهو انني سأضطر الى اعادة تعريف للخاصية في الكلاس الجديد (بالعربي ، مااستفدت شيئSad)


بالاضافة الى ذلك ، لو طبقنا العلاقتين المذكورتين بالموضوع ، سنجد ان علاقة Is- a هي التي تصلح لموضوع الPlugin
لو عرفت Plugin باسم MyPlugin فيجب ان تستورث من Class لان العلاقة ستصبح >>>
MyPlugin Is a Plugin Smile
MyPlugin can Plugin(لغويا غير ممكنة ، لذلك العلاقة لاتصلح)


اذن العلاقة هي  Is- A  فيجب الاشتقاق من Class  .. ولكن المشكلة بالـ classes  العادية ان اكوادها ثابتة ولاتناسب موضوع الPlugin لاننا نحتاج الى Type يمكننا من عمل Re-Implemented لاستعماله كقالب للcasting او لاستعماله في Plugin اخرى ..

ولكن -لحسن الحظ- Abstract class هو المنقذ Smile[/b]
PHP كود :
   abstract class  PluginBase
    
{
 
       public string Name getset; }
 
       public string Author getset; }
 
       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
 
       }
 
   
الرد }}}
#6
أساتذة اجتمعوا في موضوع........
الرد }}}
تم الشكر بواسطة: Amir_Alzubidy , الشاكي لله , ابو ليلى
#7
السلام عليكم

جزاكم الله خيرا على هذا النقاش الجميل

أحب أن اضيف بعض المعلومات بخصوص الـ interface



لا يمكن انشاء instance من interface
PHP كود :
IC c=new IC(); // Error 
لا يمكن استخدام الـ (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 IC
    
{
 
       void Print() // Error
 
       {
 
           Console.Write("Hello");
 
       }
 
   

الصحيح

PHP كود :
class IC
    
{
 
       public void Print() 
 
       {
 
           Console.Write("Hello");
 
       }
 
   

يمكن لــ interface أن يرث من interface آخر

PHP كود :
interface IB IC
    
{
 
       
    


في حال تعريف دالة داخل الــ interface سيكون لزاماً عليك استخدامها في الـ class التي يرث من الـ interface


طيب ماذا لو كان لدينا class ورث من اثنين interface وكلا الـ interface يحتويان نفس الدالة حتى لو كانت الدوال لها وظائف مختلفة؟ بالشكل التالي:
PHP كود :
interface IC
    
{
 
       void Print();
 
   }

 
   interface IB
    
{
 
       void Print();
 
   

لذا يتم حل المشكلة بالشكل التالي:

PHP كود :
class IBIC
    
{
 
       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();
 
           ((ICa).Print();
 
           ((IBa).Print();
 
       

تحياتي لكم
الرد }}}
#8
شكرا للاخ سجاد على المداخلة القيمة ، وشكرا للاخ امير الزبيدي على المشاركة والتشجيع

يبدو ان مواضيع الـ OOP تعجبكم Smile


اذن اليوم مقالة اخرى ان شاء الله
الرد }}}
تم الشكر بواسطة: Sajad , Amir_Alzubidy
#9
انتظر..... حتى افرغ ما لدي بطريقة اخرى 
هذا النقاش اللذيذ كما اشار الاخ امير يعجبني 
وما دام الاخوة يقدمون الافضل و الاجمل لذا اصبح حق علي ان اشرح ما سبق بطريقتي  Big Grin
 و اتمنى ان تعجبكم

الشرح استكمال لافكار كل الاخوة في المقال جزاهم الله كل خير و اثابهم الجنة.

مع توسع قليل من قبلي

اولا ان النوع   abstract class   يسمح بالتوريث من الكلاسات الاخرى (اي ترث منه الكلاسات الاخرى)   

ولا يمكنك انشاء نسخة مباشرة منه instantiated.

ويجب الاشارة الى ان هذا النوع يجب ان يمتلك على الاقل واحدة او اكثر من الطرق  المكتملة (اي تحتوي على كود ساسميه جسم الدالة)
و كذلك على الاقل طريقة واحدة غير مكتملة اي بدون جسم للدالة , و يجب تعريفها بالمحدد abstract

اذا كانت كل الطرق في الكلاس غير مكتملة عندها تصبح شبيهة بـ interface

ثانيا الواجهات Interface

يتم تعريفها بالكلمة المفتاحية interface و هي تحتوي على دوال غير مكتملة اي لاتحوي على جسم (تمهيد فقط)
اما عن الفائدة منها فهو في الكلاس التي ستطبق و تستفيد من هذه الطرق بعد ان تكون قد ورثت interface السابقة
و جميع الطرق و الخصائص داخل interface  كما قال الاخ سجاد هي بشكل افتراضي عامة Puplic
ساقوم بالشرح وفق الاكواد لتسهيل المهمة و لاعطاء الشرح هدف واضح
طبعا انا ساكتب اكواد #C لان المقالة في هذا القسم بالتحديد (بالنسبة لاكواد #C انا اكتبها بحكم عملي على الجافا )
لننظر الى الكود التالي الذي يعرف كلاس بسيطة من النوع abstract Class 


PHP كود :
public abstract class Product
{
 
 //fields
 
 protected string id;
 
 protected double price;
 
 //properties
 
 public abstract string ID
  
{
 
   get;
 
   set;
 
 }
 
 
 public abstract double Price
  
{
 
   get;
 
   set;
 
 
 }
 
 public abstract double CalculatePrice();


الكلاس بسيط يحتوي على حقلين مع خصائص لكل حقل  ويحتوي على طريقة واحدة تعيد المجموع


و لدي ايضا interface  يحتوي على خاصيتين و نفس الدالة السابقة


PHP كود :
public interface Iproduct
{
 
 string ID
  
{
 
   get;
 
   set;
 
 
 }
 
 
 double Price
  
{
 
   get;
 
   set;
 
 
 }
 
 double CalculatePrice();


وجه الخلاف اننا لا نستطيع تعريف متغيرات بشكل مباشر ضمن interface  كما اشار الاخ الشاكي سابقا

الان ساقوم بانشاء كلاس يقوم بتطبيق الواجهة  Iproduct (سيتم تطبيق كل الخصائص و الطرق الموروثة هذا شرط اساسي)


PHP كود :
public class implementInterfaceIproduct
{
 
 protected string id;
 
 protected double price;
 
 public string ID
  
{
 
   get
    
{
 
     return id;
 
   }
 
   set
    
{
 
     id value;
 
   }
 
 }
 
 public double price
  
{
 
   get
    
{
 
     return price;
 
   }
 
   set
    
{
 
     price value;
 
   }
 
 
 }
 
 public double CalculatePrice()
 
 {
 
   return Price 1.25;
 
 


هل رايت كيف تم توسيع الطرق و الخصائص (هكذا تستفيد من اعادة التطبيق )

الان اريد التطبيق على الكلاس Product و هو من النوع abstract Class 
لدينا هنا كلاس جديد يقوم بوراثة الكلاس السابق Product و يعيد قيادة الطرق و الخصائص كما يلي

PHP كود :
public class implementAbstractProduct
{
 
 public override string ID
  
{
 
   get
    
{
 
     return id;
 
   }
 
   set
    
{
 
     id value;
 
   }
 
 
 }
 
 public override double Price
  
{
 
   get
    
{
 
     return price;
 
   }
 
   set
    
{
 
     price value;
 
   }
 
 
 }
 
 public override double CalculatePrice
  
{
 
   return Price 1.25;
 
 }
 



اصبح بامكاننا الاستفادة من هذا الكلاس في عملنا بشكل مباشر 

بعد ذلك يمكننا انشاء نسخة جديدة من الكلاس السابق implementAbstract و استخدمها في تطبيقنا كما يلي

PHP كود :
ImplementAbstract testAbstract = New implementAbstract();
testAbstract.ID="A1";
testAbstract.Price=1000.00;
Double amt testAbstract.CalculatePrice();
Response.Write("المجموع الصافي : " " " +testAbstract.ID +" ""is"+" "+amt);
Response.Write("<br>"); 


اماذا لو احببنا ان نستفيد من الكلاس  implementInterface الذي قام بتطبيق الواجه Iproduct 
نعم يمكننا ذلك كم عملنا سابقا انظر الكود

PHP كود :
ImplementInterface testInterface = New implementInterface();
testInterface.ID="B1";
testInterface.Price=900.00;
Double Iamt testInterface.CalculatePrice();
Response.Write("المجموع الصافي : " +" "+testInterface.ID +" ""is"+" "+Iamt);
Response.Write("<br>"); 


بقي ان اقول لك بان الاعضاء المشتركة المعرفة بالطريقة (Static) لا يمكن وراثتها تحت اي ظرف كان 
لذا نحن لا نستطيع تعريفها داخل Interface .
بينما يمكنك تعريف طرق مشتركة داخل الكلاسات من النوع abstract Class 

يمكننا اضافة الطريقة التالية الى الكلاس السابق Product 

PHP كود :
public static void test()
{


بينما لا يمكننا كتابتها في Interface 

اوجه الخلاف بين Abstract Class و Interfaces



  • Abstract Class يمكن ان تحتوي على طرق كا ملة و غير كاملة , بينما Interfaces لا تحتوي الا على طرق غير مكتملة فقط تمهيد للطرق بدون كود في جسم الدالة,لذا فان Abstract Class تستطيع تطبيق الطرق (implement) بينما Interface لا تستطيع ذلك.
  • Abstract Class يمكن ان تحتوي على متغيرات (حقول) , مشيدات , مهدمات - بينما Interfaces لا يمكن تحتوي على ما سبق .
  • Abstract Class لا تدعم الوراثة المتعددة , بينما Interfaces تدعم ذلك بقوة , اذ يمكنك ان تقوم بوراثة اكثر من Interfaces في نفس الكلاس مع امكانية ورائة كلاس فقط .
  • عندما ترث من Interface سيكون لزاما عليك تطبيق كل الطرق و الخصائص التي بداخل الـ Interface , بينما انت لست ملزما بتطبيق او اعادة قيادة كل الطرق عندما ترث من  النوع Abstract Class.
  • محددات الوصول مثل (Private,Public,Protected,internal,virtual) تستطيع استخدامها مع Abstract Class , و العكس ليس صحيح مع Interface .
  • اخيرا Abstract Class اسرع في التعامل من Interface .


بقي الحديث عن Sealed Class 

ليتضح معنى Sealed Class انظر معي لهذا الكلاس
PHP كود :
public sealed class classSealed
{
 
 public string ID;
 
 public double Price;



لا يمكن اعتبار هذا النوع فئة قاعدية (Base Class) و ليست ايضا من النوع Abstract Class  
هي تستخدم تحديدا لمنع اعادة اشتقاقها
و لانها ليست فئة قاعدية فان بعض معالجات النظام تستخدمها لتسريع عمليات الوصول الى الاعضاء بداخلها


لا يمكنك اعادة اشتقاقها و ايضا لا يمكنك اعادة قيادة الطرق بداخلها و لا يمكنك وراثتها ايضا

كيف يمكنني استخدامها اذاً , بكل بساطة انشأ نسخة منها و اسند القيم و استخدم الطرق بداخلها كما هي 



PHP كود :
classSealed sc=new classSealed();
sc.ID="C1";
sc.Price=500.00;
double Samt=scCalculatePrice(); 

بقي السؤال المطروح ايهما استخدم
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
#10
كما قال اخونا "امير الزبيدي"

هذا الموضوع لازم يتغير عنوانه

لان هذي المعلومات لازم الكل يشوفها ويتعلم منها ..



بالنسبة الى Sealed Class ابدا لم اتعامل معها Big Grin
الرد }}}
تم الشكر بواسطة: Sajad , Sajad , ابو ليلى , Amir_Alzubidy


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  [نقاش] نقاش حول تطبيق الفاتورة الإلكترونية فى السعودية المرحلة الثانية Zatca Integration AmrSobhy 3 3,034 22-05-25, 03:49 AM
آخر رد: abuarab
  تعلم Interface Abu Ehab 1 2,356 19-02-18, 10:38 PM
آخر رد: sendbad100
  KeyValuePair Class Abu Ehab 1 2,241 16-12-17, 06:08 PM
آخر رد: sendbad100
  ZipFile Class Abu Ehab 1 2,448 18-11-16, 03:44 AM
آخر رد: abulayth
  [نقاش] الـ Delegate الشاكي لله 11 10,069 01-09-16, 02:27 AM
آخر رد: أبو عمر
  [C#.NET] الفرق بين #String And String Builder c Devahmedsalim 3 4,850 15-09-13, 05:50 PM
آخر رد: sooriaty03
  Tips and Tricks : الفرق بين const و static readonly RaggiTech 0 3,539 14-10-12, 03:05 PM
آخر رد: RaggiTech
  الفرق بين التعريف باستخدام overridde و new RaggiTech 0 3,075 14-10-12, 02:57 PM
آخر رد: RaggiTech

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


يقوم بقرائة الموضوع: