حقن التبعيات (Dependency Injection) في Java: دليل شامل

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا Dependency Injection أمر لا غنى عنه لمطور Java

كل مطور Java يواجه عاجلاً أم آجلاً مشكلة الترابط الصلب للكود. عندما يقوم كلاس بإنشاء نسخ من كلاسات أخرى بشكل مباشر، يصبح النظام هشاً، ويصعب اختباره وتعديله. حل هذه المشكلة هو Dependency Injection (DI)، أو حقن التبعيات. وهو أحد المبادئ الأساسية في التطوير الحديث، ويشكل الأساس لأطر عمل مثل Spring و Jakarta EE.

في هذه المقالة، سنشرح ما هو DI، وكيف يختلف عن IoC (Inversion of Control)، وسنستعرض ثلاث طرق رئيسية لحقن التبعيات في Java مع أمثلة كود توضيحية، وسنناقش لماذا هذا النمط ضروري لبناء تطبيقات قابلة للصيانة.



ما هو Dependency Injection و Inversion of Control؟

قبل الانتقال إلى الكود، من المهم فهم مفهومين أساسيين.

Inversion of Control (IoC) هو مبدأ عام يتم فيه نقل تدفق التحكم في البرنامج إلى إطار عمل أو حاوية خارجية. بدلاً من أن يقرر الكود بنفسه متى ينشئ الكائنات ويستدعي الدوال، تقوم بذلك جهة خارجية.

Dependency Injection هو تطبيق محدد لمبدأ IoC. وهو نمط يحصل فيه الكائن على تبعياته (كائنات أخرى يعتمد عليها) من مصدر خارجي، بدلاً من أن ينشئها بنفسه.

ببساطة، بدلاً من أن يقوم كلاس Car بإنشاء محرك بنفسه (new Engine())، فإنه يتلقى محركاً جاهزاً عبر المُنشئ (Constructor) أو الدالة المُعيِّنة (Setter). هذا يجعل كلاس Car مستقلاً عن التنفيذ المحدد للكلاس Engine.



ثلاث طرق لحقن التبعيات في Java

في Java، توجد ثلاث طرق رئيسية لتطبيق DI. سنستعرض كل منها باستخدام مثال لنظام إشعارات بسيط.



1. الحقن عبر المُنشئ (Constructor Injection)

هذه هي الطريقة الأكثر تفضيلاً وأماناً. يتم تمرير التبعيات عبر مُنشئ الكلاس. وهذا يضمن عدم إنشاء الكائن أبداً في حالة غير صالحة، لأن جميع التبعيات الضرورية إلزامية.

// واجهة لخدمة الإشعاراتpublic interface MessageService {    void sendMessage(String message, String recipient);}

// تنفيذ للإيميلpublic class EmailService implements MessageService { @Override public void sendMessage(String message, String recipient) { System.out.println("Email sent to " + recipient + ": " + message); }}

// كلاس يستخدم خدمة الإشعاراتpublic class NotificationSender { private final MessageService service; // التبعية

// الحقن عبر المُنشئ public NotificationSender(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { this.service.sendMessage(msg, user); }}

// الاستخدامpublic class Main { public static void main(String[] args) { MessageService emailService = new EmailService(); NotificationSender sender = new NotificationSender(emailService); // DI sender.notifyUser("user@example.com", "Hello!"); }}


2. الحقن عبر الدالة المُعيِّنة (Setter Injection)

تُستخدم هذه الطريقة عندما لا تكون التبعية إلزامية أو يمكن تغييرها بعد إنشاء الكائن. يتم تمرير التبعية عبر دالة عامة مُعيِّنة (setter).

public class NotificationSenderWithSetter {    private MessageService service; // التبعية غير إلزامية

// الدالة المُعيِّنة للحقن public void setMessageService(MessageService service) { this.service = service; }

public void notifyUser(String user, String msg) { if (service != null) { this.service.sendMessage(msg, user); } else { System.out.println("No service configured!"); } }}

// الاستخدام

المدونات

توصيات الكتب