حقن التبعية في جافا: دليل شامل للمبتدئين

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

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

ابدأ الدورة

مقدمة: مشكلة الاقتران القوي في جافا

\n\n

تخيل أنك تكتب تطبيقًا لإرسال الإشعارات. في صف NotificationService الخاص بك، يتم إنشاء كائن EmailSender مباشرة. كل شيء يعمل بشكل رائع، حتى يطلب منك العميل يومًا ما إضافة دعم إشعارات SMS و Push. سيتعين عليك إعادة كتابة NotificationService، وتغيير المُنشئات، وإضافة شروط جديدة. يصبح الكود هشًا، ويصعب اختباره وتوسيعه.

\n\n

هذه هي المشكلة الكلاسيكية للـ الاقتران القوي (tight coupling). الحل يسمى Dependency Injection (حقن التبعية) — وهو أحد المبادئ الأساسية للتصميم في جافا وأساس أطر العمل مثل Spring. في هذه المقالة، سنشرح ما هو Dependency Injection بكلمات بسيطة، وكيفية تنفيذه، ولماذا لا يمكن لأي مطور جافا محترف الاستغناء عنه.

\n\n

ما هو Dependency Injection بكلمات بسيطة؟

\n\n

Dependency Injection (DI) هو نمط تصميم يحصل فيه الكائن على تبعياته من الخارج، بدلاً من إنشائها بنفسه. بدلاً من كتابة new EmailSender() داخل الصف، فإنك «تحقن» كائنًا جاهزًا عبر المُنشئ، أو setter، أو واجهة.

\n\n

يرتبط DI ارتباطًا وثيقًا بمبدأ Inversion of Control (IoC) — عكس التحكم. إذا كان صفك في السابق يدير إنشاء التبعيات بنفسه، فإن التحكم يُنقل الآن إلى حاوية خارجية (مثل Spring IoC).

\n\n

المزايا الرئيسية لـ DI:

\n
    \n
  • الاقتران الضعيف (loose coupling) — تعتمد الصفوف على التجريدات، وليس على التطبيقات الملموسة.
  • \n
  • تبسيط الاختبار — يمكن استبدال التبعيات بسهولة بـ mocks أو stubs.
  • \n
  • إعادة استخدام الكود — يمكن استخدام نفس الخدمة في سياقات مختلفة.
  • \n
  • سهولة الصيانة — تغيير التطبيق لا يتطلب تعديل الصفوف المستهلكة.
  • \n
\n\n

أنواع حقن التبعية في جافا

\n\n

هناك ثلاث طرق رئيسية لتنفيذ Dependency Injection في جافا. دعنا ننظر إلى كل منها بمثال.

\n\n

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

\n\n

الطريقة الأكثر شيوعًا والموصى بها. يتم تمرير التبعيات عبر معاملات المُنشئ وتُحفظ كحقول للصف (عادةً final).

\n\n
// واجهة لإرسال الرسائل\npublic interface MessageSender {\n    void send(String message, String recipient);\n}\n\n// تطبيق ملموس — Email\npublic class EmailSender implements MessageSender {\n    @Override\n    public void send(String message, String recipient) {\n        System.out.println("إرسال بريد إلكتروني: " + message + " إلى " + recipient);\n    }\n}\n\n// خدمة تستخدم DI عبر المُنشئ\npublic class NotificationService {\n    private final MessageSender sender;\n\n    // يتم حقن التبعية عبر المُنشئ\n    public NotificationService(MessageSender sender) {\n        this.sender = sender;\n    }\n\n    public void notifyUser(String message, String userEmail) {\n        sender.send(message, userEmail);\n    }\n}\n\n// الاستخدام\npublic class Main {\n    public static void main(String[] args) {\n        MessageSender emailSender = new EmailSender();\n        NotificationService service = new NotificationService(emailSender);\n        service.notifyUser("مرحبًا بك!", "user@example.com");\n    }\n}
\n\n

الإيجابيات: يتم إنشاء الكائن في حالة جاهزة تمامًا، والتبعيات غير قابلة للتغيير (immutable)، وسهلة الاختبار.

\n\n

2. الحقن عبر setter (Setter Injection)

\n\n

يتم تمرير التبعيات عبر دوال setter بعد إنشاء الكائن. يُستخدم غالبًا للتبعيات الاختيارية.

\n\n
public class NotificationService {\n    private MessageSender sender;\n\n    // دالة setter لحقن التبعية\n    public void setSende                

المدونات

توصيات الكتب