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

أساسيات Dependency Injection

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

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

بدون DI، تنشئ class تبعياتها بنفسها، مما يجعل تغييرها أو اختبارها أمرًا صعبًا:

public class OrderService
{
    private EmailSender sender = new EmailSender();  // مقترن بإحكام
    
    public void PlaceOrder() => sender.Send("Order placed");
}

باستخدام DI، يتم تمرير التبعيات من خلال المُنشئ:

public interface IMessageSender
{
    void Send(string message);
}

public class EmailSender : IMessageSender
{
    public void Send(string message) => Console.WriteLine("Email: " + message);
}

public class OrderService
{
    private IMessageSender sender;
    
    public OrderService(IMessageSender sender)
    {
        this.sender = sender;
    }
    
    public void PlaceOrder() => sender.Send("Order placed");
}

الآن لا يعرف OrderService ولا يهتم بما إذا كان يستخدم البريد الإلكتروني أو SMS أو مرسلًا وهميًا للاختبار. يتم إجراء injected لـ dependency عند إنشاء الكائن:

IMessageSender emailSender = new EmailSender();
OrderService service = new OrderService(emailSender);
service.PlaceOrder();  // البريد الإلكتروني: تم تقديم الطلب

يتبع هذا النمط مبدأ الاعتماد على التجريدات (الواجهات) بدلًا من التنفيذات الملموسة. ويتيح تبديل التنفيذات دون تعديل الفئة التي تستخدمها، وهو أمر ضروري لاختبار الوحدات والحفاظ على بنيات مرنة.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لتسجيل السجلات يوضّح قوة حقن الاعتماديات. بدلًا من ترميز كيفية كتابة السجلات بشكل ثابت، ستنشئ فئة Logger مرنة يمكنها العمل مع أي وجهة لتسجيل السجلات - وحدة التحكم، أو محاكاة ملف، أو أي شيء آخر - من دون معرفة التفاصيل.

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

  • ILogWriter.cs: عرّف واجهة باسم ILogWriter في مساحة الأسماء Logging. تمثّل هذه الواجهة العقد الخاص بأي وجهة لتسجيل السجلات، ويجب أن تحتوي على method واحدة Write(string message) تُرجع سلسلة تصف المكان الذي كُتبت فيه الرسالة.
  • LogWriters.cs: أنشئ تطبيقين ملموسين للواجهة ILogWriter في مساحة الأسماء Logging:
    • ConsoleLogWriter - تُرجع Write الخاصة بها Console: {message}
    • FileLogWriter - تتلقى اسم ملف من خلال constructor الخاصة بها، وتُرجع Write الخاصة بها File[{filename}]: {message}
  • Logger.cs: أنشئ فئة Logger في مساحة الأسماء Logging، وتتلقى dependency الخاصة بها من خلال حقن الاعتمادية في constructor. يجب أن تقوم Logger بما يلي:
    • قبول ILogWriter من خلال constructor الخاصة بها وتخزينه في field خاصة
    • امتلاك method باسم Log(string message) تفوّض المهمة إلى الكاتب injected وتُرجع النتيجة
  • Program.cs: وضّح حقن الاعتماديات من خلال إنشاء كاتبي سجلات مختلفين - أحدهما باستخدام ConsoleLogWriter والآخر باستخدام FileLogWriter. وضّح كيف تتصرف الفئة نفسها Logger بشكل مختلف بناءً على الاعتمادية التي يتم حقنها.

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

  • اسم الملف الخاص بكاتب السجلات للملف
  • الرسالة المراد تسجيلها

أنشئ Logger باستخدام ConsoleLogWriter وسجّل الرسالة. ثم أنشئ Logger آخر باستخدام FileLogWriter (مع استخدام اسم الملف من الإدخال) وسجّل الرسالة نفسها. اطبع كل نتيجة في سطر خاص بها.

على سبيل المثال، إذا كان المدخلان هما app.log وSystem started، فيجب أن يكون الناتج:

Console: System started
File[app.log]: System started

لاحظ أن فئة Logger لا تتغير أبدًا - فهي تعمل مع أي تطبيق للواجهة ILogWriter. هذا هو جوهر حقن الاعتماديات: تعتمد Logger على تجريد (الواجهة)، ويجري "injected" التطبيق الملموس من الخارج. يمكنك بسهولة إضافة DatabaseLogWriter أو CloudLogWriter لاحقًا من دون تعديل فئة Logger على الإطلاق!

جرّب بنفسك

using System;
using Logging;

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

        // TODO: أنشئ Logger مع ConsoleLogWriter وسجّل الرسالة
        // اطبع النتيجة

        // TODO: أنشئ Logger آخر مع FileLogWriter (باستخدام filename) وسجّل نفس الرسالة
        // اطبع النتيجة
    }
}
quiz iconاختبر نفسك

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

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

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