حقن التبعيات في Go: المبادئ، الأمثلة وأفضل الممارسات

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

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

ابدأ الدورة

Dependency Injection في Go: المبادئ والأمثلة وأفضل الممارسات



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



ما هو Dependency Injection؟

Dependency Injection هو نمط تصميم (design pattern) حيث يحصل الكائن على تبعياته من الخارج، بدلاً من إنشائها بنفسه. الهدف الرئيسي هو تقليل الاقتران (coupling) بين المكونات وزيادة قابلية اختبار الكود.



في Go، يتم تنفيذ DI عن طريق تمرير التبعيات إلى الهياكل (structs) أو الدوال. لنلق نظرة على مثال بسيط بدون DI:



package main

import "fmt"

type Logger struct{}

func (l *Logger) Log(message string) { fmt.Println("Log:", message)}

type Service struct { logger *Logger}

func NewService() *Service { return &Service{ logger: &Logger{}, // ارتباط صلب }}

func (s *Service) DoSomething() { s.logger.Log("Doing something")}


والآن نفس المثال باستخدام DI:



package main

import "fmt"

type Logger interface { Log(message string)}

type ConsoleLogger struct{}

func (l *ConsoleLogger) Log(message string) { fmt.Println("Log:", message)}

type Service struct { logger Logger // التبعية عبر الواجهة}

func NewService(logger Logger) *Service { return &Service{logger: logger} // حقن التبعية}

func (s *Service) DoSomething() { s.logger.Log("Doing something")}


مزايا Dependency Injection في Go

  • قابلية الاختبار: يمكنك بسهولة استبدال التبعيات الحقيقية بـ mocks أو stubs في الاختبارات.
  • المرونة: تغيير سلوك التطبيق يقتصر على استبدال تنفيذ التبعية.
  • نظافة الكود: يصبح الكود أكثر نمطية (modular)، حيث يتحمل كل هيكل مسؤولية منطقه فقط.
  • تبسيط إعادة الهيكلة: يتم الإعلان عن التبعيات بشكل صريح، مما يسهل فهم الكود وتعديله.


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

في Go، توجد عدة طرق لتنفيذ DI. دعنا نستعرض الأساسيات.



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

الطريقة الأكثر شيوعًا. يتم تمرير التبعيات عبر دالة المُنشئ (NewSomething()).



type UserRepository interface {    FindByID(id int) (*User, error)}

type UserService struct { repo UserRepository}

func NewUserService(repo UserRepository) *UserService { return &UserService{repo: repo}}


2. الحقن عبر حقول الهيكل (Field Injection)

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



type UserService struct {    Repo UserRepository}

func main() { svc := &UserService{} svc.Repo = &PostgresRepository{}}


3. الحقن عبر الدوال (Method Injection)

يتم تمرير التبعية إلى الدالة، وليس إلى المُنشئ. مفيد للتبعيات المؤقتة.



type UserService struct{}

func (s *UserService) GetUser(repo UserRepository, id int) (*User, error) { return repo.FindByID(id)}


مثال: بناء خادم HTTP مع DI

لنلق نظرة على مثال أكثر تعقيدًا — إنشاء خادم HTTP مع حقن التبعيات.



package main

import ( "encoding/json" "net/http")

// نحدد الواجهاتtype UserRepository int

المدونات

توصيات الكتب