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

الواجهة كعقد

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

يساعدك التفكير في الواجهات باعتبارها عقودًا على تصميم برامج Go أفضل. عندما تقبل دالة نوع واجهة، فهي تقول: "لا يهمني نوع البيانات الفعلي الذي تمنحني إياه، ما دام يفي بهذا العقد."

يتيح لك هذا التفكير القائم على العقود كتابة دوال تركّز على السلوك بدلًا من أنواع محددة. تأمّل دالة تحتاج إلى معالجة البيانات من مصادر متنوعة:

type DataSource interface {
    FetchData() string
}

func ProcessData(src DataSource) {
    data := src.FetchData()
    fmt.Println("Processing:", data)
}

لا تعرف الدالة ProcessData ولا تهتم بما إذا كانت تتلقى اتصالًا بقاعدة بيانات، أو عميل API، أو قارئًا للملفات. فهي تتطلب فقط أن يتمكن الإدخال من استدعاء FetchData(). ويعمل أي نوع يلتزم بهذا contract.

type Database struct{ ConnectionString string }
func (d Database) FetchData() string { return "data from DB" }

type APIClient struct{ Endpoint string }
func (a APIClient) FetchData() string { return "data from API" }

func main() {
    db := Database{ConnectionString: "localhost"}
    api := APIClient{Endpoint: "https://api.example.com"}
    
    ProcessData(db)   // يعمل!
    ProcessData(api)  // يعمل أيضاً!
}

يجعل نهج contract شيفرتك أكثر قابلية للاختبار أيضًا. أثناء الاختبار، يمكنك إنشاء نوع وهمي يفي بمتطلبات interface من دون الحاجة إلى قواعد بيانات حقيقية أو اتصالات بالشبكة. لا تعرف function الخاضعة للاختبار الفرق، لأن contract قد استُوفي.

challenge icon

التحدي

سهل

لنَبْنِ نظام notification يوضّح كيف تعمل interfaces بوصفها contract. ستنشئ interface باسم Notifier يحدّد ما يعنيه إرسال notification، ثم تنفّذ قنوات notification متعددة تلتزم جميعها بهذا contract.

ستنظّم الكود عبر ملفين:

  • notifiers.go: Define interface باسم Notifier مع method واحدة هي Notify(message string) string. ثم أنشئ ثلاثة structs مختلفة تستوفي هذا contract:
    • ConsoleNotifier مع field باسم Prefix
    • FileNotifier مع field باسم Filename
    • WebhookNotifier مع field باسم URL
    يجب أن ينفّذ كل struct method المسماة Notify لإرجاع string يصف كيفية إرسال notification.
  • main.go: أنشئ function باسم BroadcastAlert تقبل شريحة من قيم Notifier وmessage من نوع string. يجب أن تستدعي هذه function Notify على كل notifier وتطبع النتائج. اقرأ الإعدادات من الإدخال، وأنشئ أنواع notifier الثلاثة، ثم أرسل alert عبرها جميعًا.

سيتم توفير المدخلات التالية:

  • السطر 1: بادئة Console
  • السطر 2: Filename
  • السطر 3: عنوان URL الخاص بـ Webhook
  • السطر 4: message الخاص بـ Alert

يجب أن تُرجع methods المسماة Notify strings بالتنسيقات التالية:

  • ConsoleNotifier: [Prefix] [message]
  • FileNotifier: Writing to [Filename]: [message]
  • WebhookNotifier: POST [URL]: [message]

على سبيل المثال، عند إعطاء ALERT: وlog.txt وhttps://hooks.example.com وServer down!، يجب أن يكون الناتج:

ALERT: Server down!
Writing to log.txt: Server down!
POST https://hooks.example.com: Server down!

تكمن قوة هذا التصميم في أن function المسماة BroadcastAlert لا تعرف أنواع notifier المحددة ولا تهتم بها. فهي تتطلب فقط أن يفي كل واحد منها بـ contract الخاص بـ Notifier. ويمكنك إضافة SlackNotifier أو EmailNotifier لاحقًا دون تغيير function الخاصة بالبث إطلاقًا.

جرّب بنفسك

package main

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

// BroadcastAlert يرسل رسالة عبر جميع notifiers
// TODO: نفّذ هذه الدالة لـ:
// - اقبل slice من قيم Notifier ورسالة string
// - استدعِ Notify على كل notifier واطبع النتائج
func BroadcastAlert(notifiers []Notifier, message string) {
	// TODO: مرّ عبر notifiers واطبع نتيجة كل إشعار
}

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	// اقرأ بادئة وحدة التحكم
	scanner.Scan()
	prefix := scanner.Text()
	
	// اقرأ اسم الملف
	scanner.Scan()
	filename := scanner.Text()
	
	// اقرأ عنوان URL للـ webhook
	scanner.Scan()
	url := scanner.Text()
	
	// اقرأ رسالة التنبيه
	scanner.Scan()
	message := scanner.Text()
	
	// TODO: أنشئ مثيلات لجميع أنواع الـ notifier الثلاثة
	// - ConsoleNotifier مع الـ prefix
	// - FileNotifier مع اسم الملف
	// - WebhookNotifier مع الـ URL
	
	// TODO: أنشئ شريحة من Notifier تحتوي على جميع المُبلِّغات الثلاثة
	
	// TODO: استدعِ BroadcastAlert مع المُبلِّغات والرسالة
	
	_ = prefix
	_ = filename
	_ = url
	_ = message
	fmt.Println("TODO: Implement the solution")
}
quiz iconاختبر نفسك

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

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

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