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

التركيب بدلاً من الوراثة

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

ينشئ التوريث اقترانًا وثيقًا بين الفئات. عندما ترث Car من Vehicle، يمكن لأي تغيير في Vehicle أن يتسبب في تعطل Car. يوفّر التركيب بديلًا أكثر مرونة: فبدلًا من توريث السلوك، تحتوي الفئة على كائنات توفّر ذلك السلوك.

تخيّل شخصية في لعبة يمكنها التحرك والهجوم. باستخدام الوراثة، قد تنشئ تسلسلاً هرميًا معقدًا. أما باستخدام التركيب، فكل ما عليك هو تزويد الشخصية بالمكوّنات التي تحتاج إليها:

public class MovementBehavior
{
    public void Move() => Console.WriteLine("Moving...");
}

public class AttackBehavior
{
    public void Attack() => Console.WriteLine("Attacking!");
}

public class Character
{
    private MovementBehavior movement = new MovementBehavior();
    private AttackBehavior attack = new AttackBehavior();
    
    public void Move() => movement.Move();
    public void Attack() => attack.Attack();
}

الفرق الأساسي هو العلاقة. تمثّل الوراثة علاقة "is-a" (فالـ Dog is an Animal)، بينما يمثّل التركيب علاقة "has-a" (فإن Character has سلوك movement). يتيح لك التركيب تبديل السلوكيات أثناء وقت التشغيل، ودمج الإمكانات بحرية، وتجنّب مشكلة الفئة الأساسية الهشّة.

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

challenge icon

التحدي

سهل

لنبنِ نظامًا للإشعارات يوضّح قوة التركيب مقارنةً بالوراثة. بدلًا من إنشاء تسلسل هرمي معقّد من فئات الإشعارات، ستقوم بتركيب NotificationSender من خلال تزويده بمكوّنات سلوك قابلة للتبديل.

ستنظّم الشيفرة عبر ثلاثة ملفات:

  • Behaviors.cs: أنشئ فئتَي سلوك في مساحة الاسم Notifications تتوليان جوانب مختلفة من إرسال الإشعارات:
    • FormattingBehavior - تحتوي على أسلوب Format(string message) يعيد الرسالة محاطةً بـ [ALERT] في البداية و [END] في النهاية
    • DeliveryBehavior - تحتوي على أسلوب Deliver(string channel, string message) يعيد سلسلة نصية بالتنسيق Sending via {channel}: {message}
  • NotificationSender.cs: أنشئ فئة NotificationSender في مساحة الاسم Notifications تستخدم التركيب لدمج السلوكيات. يجب أن يقوم المرسِل بما يلي:
    • يحتوي على مثيلين من كلٍّ من FormattingBehavior وDeliveryBehavior كحقلين خاصين
    • يحتوي على خاصية Channel (من النوع string) تخزّن اسم قناة التسليم
    • يحتوي على مُنشئ يقبل اسم القناة
    • يحتوي على أسلوب Send(string message) ينسّق الرسالة أولًا باستخدام سلوك التنسيق، ثم يسلّمها باستخدام سلوك التسليم، ويعيد النتيجة النهائية
  • Program.cs: في ملفك الرئيسي، أنشئ NotificationSender باستخدام قناة من الإدخال، ثم أرسل رسالة من الإدخال. اطبع النتيجة لإظهار كيفية عمل السلوكيات المركّبة معًا.

ستتلقى مدخلين:

  • اسم قناة التسليم (مثل Email وSMS)
  • الرسالة المراد إرسالها

اطبع نتيجة استدعاء Send() على مرسل الإشعارات.

على سبيل المثال، إذا كان الإدخالان هما Email وServer is down، فيجب أن يكون الناتج:

Sending via Email: [ALERT] Server is down [END]

لاحظ أن NotificationSender لا يرث من أي شيء، بل "has" ببساطة سلوكَي التنسيق والتسليم. ويعني أسلوب التركيب هذا أنه يمكنك بسهولة تبديل أيٍّ من السلوكين دون تغيير فئة المرسِل، أو إعادة استخدام هذين السلوكين في فئات مختلفة تمامًا!

جرّب بنفسك

using System;
using Notifications;

class Program
{
    public static void Main(string[] args)
    {
        // اقرأ المدخلات
        string channel = Console.ReadLine();
        string message = Console.ReadLine();

        // TODO: أنشئ NotificationSender بالقناة
        
        // TODO: أرسل الرسالة واطبع النتيجة
        
    }
}
quiz iconاختبر نفسك

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

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

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