Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

الواجهة مقابل الفئة المجردة (Abstract Class)

جزء من قسم البرمجة كائنية التوجه في رحلة C# على Coddy. الدرس 26 من 70.

تتيح لك كلٌّ من الواجهات والفئات المجردة Define عقودًا يجب على الفئات الأخرى اتباعها، لكن لكلٍّ منها أغراض مختلفة وإمكانات مميزة.

تحدّد interface ما يجب أن يفعله الصنف، من دون أي تنفيذ. إنها عقد خالص:

public interface IFlyable
{
    void Fly();
}

public class Bird : IFlyable
{
    public void Fly()
    {
        Console.WriteLine("Flapping wings");
    }
}

يمكن أن توفّر الفئة abstract عقدًا وتنفيذًا مشتركًا في آنٍ واحد. إنها مخطط جزئي:

public abstract class Vehicle
{
    public string Brand { get; set; }
    
    public void StartEngine()
    {
        Console.WriteLine("Engine started");
    }
    
    public abstract void Drive();  // يجب تنفيذه
}

public class Car : Vehicle
{
    public override void Drive()
    {
        Console.WriteLine("Driving on roads");
    }
}

تتمثل الاختلافات الرئيسية في قواعد الوراثة والغرض.

يمكن للفئة تنفيذ عدة واجهات، لكنها لا ترث إلا من فئة abstract واحدة.

استخدم واجهة عندما تحتاج الفئات غير المرتبطة إلى مشاركة السلوك (مثل IFlyable للطيور والطائرات). استخدم فئة مجردة عندما تشترك الفئات المرتبطة في تعليمات برمجية وحالة مشتركتين (مثل المركبات التي تشترك في آلية تشغيل المحرك).

يمكن أن تحتوي abstract class على constructor وحقول ومعدِّلات وصول للأعضاء. تقليديًا، لم يكن ذلك ممكنًا في interface، رغم أن C# الحديثة تسمح بالتطبيقات الافتراضية.

عند الشك، فضّل الواجهات لتحقيق المرونة - يمكنك دائمًا إضافة فئة abstract لاحقًا إذا أصبح التنفيذ المشترك ضروريًا.

challenge icon

التحدي

سهل

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

ستنظّم التعليمات البرمجية في أربعة ملفات:

  • IPlayable.cs: عرّف interface باسم IPlayable في مساحة الأسماء Media. تمثّل هذه الواجهة العقد لأي شيء يمكنه تشغيل الوسائط، سواء كان هاتفًا أو تلفازًا أو مشغّل موسيقى مخصّصًا. يجب أن تعلن عن method واحدة هي Play() تُرجع string.
  • MediaFile.cs: عرّف فئة abstract باسم MediaFile في مساحة الأسماء Media. يمثّل هذا الأساس المشترك لجميع ملفات الوسائط. يجب أن يحتوي على الخاصية Title (من النوع string) والخاصية Duration (من النوع int، وتمثّل عدد الثواني). أضف constructor يعيّن القيمتين كلتيهما. أضف method concrete باسم GetInfo() تُرجع "{Title} ({Duration}s)". كذلك أعلن عن method abstract باسم GetType() تُرجع string؛ إذ سيحدّد كل نوع من الوسائط نوع الملف الذي يمثّله.
  • AudioFile.cs: عرّف فئة AudioFile في مساحة الأسماء Media، بحيث ترث من MediaFile وتطبّق IPlayable. أضف الخاصية Artist (من النوع string). يجب أن يقبل constructor العنوان والمدة واسم الفنان. نفّذ override للـ GetType() بحيث تُرجع "Audio". نفّذ Play() بحيث تُرجع "Playing audio: {Title} by {Artist}".
  • Program.cs: في ملفك الرئيسي، أنشئ AudioFile باستخدام قيم الإدخال. وضّح كلا جانبي الفئة: استدعِ GetInfo() وGetType() (الموروثتين من الفئة abstract)، ثم استدعِ Play() (من interface). خزّن ملف الصوت في متغيّر من النوع IPlayable واستدعِ Play() مرة أخرى لإظهار تعدد الأشكال عبر interface.

ستتلقى ثلاث قيم إدخال:

  • عنوان الأغنية
  • المدة بالثواني
  • اسم الفنان

اطبع الناتج بهذا التنسيق:

Info: {GetInfo() result}
Type: {GetType() result}
Direct: {Play() result}
Via Interface: {Play() result from IPlayable variable}

على سبيل المثال، إذا كانت قيم الإدخال هي Bohemian Rhapsody و354 وQueen، فيجب أن يكون الناتج:

Info: Bohemian Rhapsody (354s)
Type: Audio
Direct: Playing audio: Bohemian Rhapsody by Queen
Via Interface: Playing audio: Bohemian Rhapsody by Queen

لاحظ كيف تستفيد AudioFile من النهجين: فهي ترث التنفيذ المشترك (GetInfo()) من الفئة abstract، وفي الوقت نفسه تفي بعقد IPlayable. توفّر الفئة abstract إعادة استخدام التعليمات البرمجية لأنواع الوسائط المرتبطة، بينما تتيح interface لأي فئة غير مرتبطة أن تكون "playable" من دون مشاركة تسلسل هرمي للوراثة.

جرّب بنفسك

using System;
using Media;

class Program
{
    public static void Main(string[] args)
    {
        // اقرأ قيم الإدخال
        string title = Console.ReadLine();
        int duration = Convert.ToInt32(Console.ReadLine());
        string artist = Console.ReadLine();
        
        // TODO: أنشئ AudioFile باستخدام قيم الإدخال
        
        // TODO: اطبع Info: متبوعًا بنتيجة GetInfo()
        
        // TODO: اطبع Type: متبوعًا بنتيجة GetType()
        
        // TODO: اطبع Direct: متبوعًا بنتيجة Play()
        
        // TODO: خزّن ملف الصوت في متغير IPlayable
        
        // TODO: اطبع Via Interface: متبوعًا بنتيجة Play() من متغير IPlayable
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس البرمجة كائنية التوجه

تدرّب بنفسك: مترجم C# عبر الإنترنت