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

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

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

ابدأ الدورة

مقدمة: لماذا يعتبر حقن التبعية مهماً في Go؟

\n\n

Go (Golang) هي لغة تشتهر ببساطتها وأدائها. ومع ذلك، عندما يبدأ مشروعك في النمو، يمكن أن يتحول الكود بسرعة إلى "سباغيتي"، حيث تكون الدوال والهياكل مرتبطة ببعضها البعض بشكل صارم. هنا يأتي دور حقن التبعية (DI).

\n\n

بالنسبة للمطورين المبتدئين، قد يبدو DI مفهوماً معقداً من عالم Java أو C#. لكن في Go، يتم تنفيذ هذا النمط بأناقة وبدون أطر عمل. في هذه المقالة، سنشرح ما هو حقن التبعية، ولماذا نحتاجه، وكيفية تطبيقه بشكل صحيح في Go مع أمثلة عملية.

\n\n

إذا كنت تريد كتابة كود قابل للاختبار ومرن وقابل للصيانة في Golang، فهذه المقالة لك.

\n\n

ما هو حقن التبعية (DI)؟

\n\n

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

\n\n

بكلمات بسيطة: بدلاً من كتابة myService := MyService{} داخل الكود الخاص بك، تقوم "بحقن" نسخة جاهزة من myService في المُنشئ أو الدالة.

\n\n

المشكلة بدون DI

\n\n

تخيل أن لديك تطبيقاً لإرسال الإشعارات. بدون DI، قد يبدو الكود كالتالي:

\n\n
package main\n\nimport "fmt"\n\ntype EmailNotifier struct{}\n\nfunc (e EmailNotifier) Send(message string) {\n    fmt.Println("إرسال بريد إلكتروني:", message)\n}\n\ntype UserService struct {\n    notifier EmailNotifier // ارتباط صارم\n}\n\nfunc NewUserService() *UserService {\n    return &UserService{\n        notifier: EmailNotifier{}, // إنشاء التبعية داخلياً\n    }\n}\n\nfunc (u *UserService) NotifyUser(message string) {\n    u.notifier.Send(message)\n}\n\nfunc main() {\n    service := NewUserService()\n    service.NotifyUser("مرحباً!")\n}\n
\n\n

ما المشكلة هنا؟

\n
    \n
  • ارتباط صارم: UserService مرتبط بـ EmailNotifier. إذا أردت استبدال البريد الإلكتروني بـ SMS، ستحتاج لتغيير كود UserService.
  • \n
  • صعوبة الاختبار: لا يمكنك اختبار UserService دون إرسال بريد إلكتروني حقيقي. هذا أمر بالغ الأهمية لاختبارات الوحدة.
  • \n
\n\n

الحل مع DI

\n\n

الآن سنعيد كتابة نفس المثال باستخدام حقن التبعية:

\n\n
package main\n\nimport "fmt"\n\n// Notifier — واجهة تجرد إرسال الإشعارات\ntype Notifier interface {\n    Send(message string)\n}\n\ntype EmailNotifier struct{}\n\nfunc (e EmailNotifier) Send(message string) {\n    fmt.Println("إرسال بريد إلكتروني:", message)\n}\n\ntype SMSNotifier struct{}\n\nfunc (s SMSNotifier) Send(message string) {\n    fmt.Println("إرسال SMS:", message)\n}\n\ntype UserService struct {\n    notifier Notifier // تبعية عبر الواجهة\n}\n\n// NewUserService يستقبل Notifier من الخارج\nfunc NewUserService(n Notifier) *UserService {\n    return &UserService{notifier: n}\n}\n\nfunc (u *UserService) NotifyUser(message string) {\n    u.notifier.Send(message)\n}\n\nfunc main() {\n    // حقن EmailNotifier\n    emailService := NewUserService(EmailNotifier{})\n    emailService.NotifyUser("مرحباً عبر البريد الإلكتروني!")\n\n    // حقن SMSNotifier — دون تغيير UserService!\n    smsService := NewUserService(SMSNotifier{})\n    smsService.NotifyUser("مرحباً عبر SMS!")\n}\n
\n\n

الآن UserService لا يعرف أي مُشعِر يتم استخدامه بالضبط. هو فقط يستدعي دالة Send على الكائن المُمرر. هذا هو حقن التبعية.

\n\n

المزايا الرئيسية لـ DI في Go

\n\n

1. قابلية الاختبار (كائنات وهمية Mock)

\n\n

يجعل DI الكود الخاص بك مثالياً لاختبارات الوحدة. يمكنك بسهولة استبدال التبعية الحقيقية بـ "كائن وهمي" (mock).

\n\n
package main\n\nimport "testing"\n\ntype MockNotifier struc                

المدونات

توصيات الكتب