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

حقن التبعية

جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 45 من 107.

حقن التبعيات هو تقنية يتلقى فيها هيكل تبعياته من الخارج بدلاً من إنشائها داخليًا. في Go، تجعل الواجهات هذا النمط طبيعيًا وقويًا.

بدلاً من تضمين تنفيذ محدد بشكل ثابت داخل هيكل، فإنك تقبل interface. يتيح لك ذلك تبديل عمليات التنفيذ دون تغيير تعليمات الهيكل البرمجية:

type Notifier interface {
    Send(message string) string
}

type EmailNotifier struct{}
func (e EmailNotifier) Send(message string) string {
    return "Email: " + message
}

type SMSNotifier struct{}
func (s SMSNotifier) Send(message string) string {
    return "SMS: " + message
}

أنشئ الآن بنية تعتمد على الواجهة، وليس على نوع ملموس:

type OrderService struct {
    notifier Notifier  // تم حقن التبعية عبر الواجهة
}

func NewOrderService(n Notifier) *OrderService {
    return &OrderService{notifier: n}
}

func (o *OrderService) PlaceOrder(item string) string {
    return o.notifier.Send("Order placed: " + item)
}

لا تعرف OrderService ولا تهتم بما إذا كانت تستخدم البريد الإلكتروني أو الرسائل النصية القصيرة. تقوم بحقن dependency عند إنشاء الخدمة:

func main() {
    emailService := NewOrderService(EmailNotifier{})
    fmt.Println(emailService.PlaceOrder("Book"))  // Email: تم تقديم الطلب: Book
    
    smsService := NewOrderService(SMSNotifier{})
    fmt.Println(smsService.PlaceOrder("Phone"))   // SMS: تم تقديم الطلب: Phone
}

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

challenge icon

التحدي

سهل

لنبنِ نظام تسجيل يوضّح قوة حقن التبعيات. ستنشئ خدمة يمكنها كتابة السجلات إلى وجهات مختلفة، من دون أن تعرف الخدمة أو تهتم بالمكان الذي تذهب إليه هذه السجلات فعليًا.

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

  • logger.go: عرّف واجهة Logger التي تتطلب أسلوبًا Log(message string) string. ثم أنشئ تطبيقين مختلفين للتسجيل:
    • ConsoleLogger مع حقل Prefix. يعيد أسلوب Log الخاص به القيمة [CONSOLE] [Prefix]: [message]
    • FileLogger مع حقل Filename. يعيد أسلوب Log الخاص به القيمة [FILE:[Filename]] [message]
  • service.go: أنشئ بنية AppService تعتمد على واجهة Logger (وليس نوعًا ملموسًا). أدرج دالة مُنشئ NewAppService تقبل Logger وتعيد مؤشرًا إلى AppService. امنح AppService أسلوبًا يُسمى DoWork(task string) string يستخدم المسجّل المحقون لتسجيل الرسالة Processing: [task] ويعيد أيًا كانت القيمة التي يعيدها المسجّل.
  • main.go: اقرأ الإعدادات من الإدخال، وأنشئ نوعَي المسجّلين، واحن كل واحد منهما في مثيل AppService منفصل، واستدعِ DoWork على كل خدمة باستخدام المهمة المقدّمة. اطبع النتيجة من كل استدعاء للخدمة.

ستُقدَّم المدخلات التالية:

  • السطر 1: بادئة مسجّل وحدة التحكم
  • السطر 2: اسم ملف مسجّل الملفات
  • السطر 3: المهمة المطلوب معالجتها

على سبيل المثال، عند إعطاء INFO وapp.log وuser authentication، يجب أن يكون الناتج:

[CONSOLE] INFO: Processing: user authentication
[FILE:app.log] Processing: user authentication

لاحظ أن AppService لا يعرف ما إذا كان يسجّل في وحدة تحكم أم في ملف. فهو يستدعي ببساطة Log على أي مسجّل تم حقنه. هذه المرونة هي جوهر حقن التبعيات: تعمل شيفرة الخدمة نفسها مع تطبيقات تسجيل مختلفة تمامًا.

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// اقرأ بادئة مسجل وحدة التحكم
	prefix, _ := reader.ReadString('\n')
	prefix = prefix[:len(prefix)-1]
	
	// اقرأ اسم ملف مسجل الملفات
	filename, _ := reader.ReadString('\n')
	filename = filename[:len(filename)-1]
	
	// اقرأ المهمة المراد معالجتها
	task, _ := reader.ReadString('\n')
	if len(task) > 0 && task[len(task)-1] == '\n' {
		task = task[:len(task)-1]
	}
	
	// TODO: أنشئ ConsoleLogger بالبادئة
	
	// TODO: أنشئ FileLogger باسم الملف
	
	// TODO: أنشئ AppService مع حقن ConsoleLogger
	
	// TODO: أنشئ AppService آخر مع حقن FileLogger
	
	// TODO: استدعِ DoWork على كل خدمة مع المهمة واطبع النتائج
	fmt.Println("result1")
	fmt.Println("result2")
}
quiz iconاختبر نفسك

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

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

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