أنماط التصميم المتقدمة في Go: من النظرية إلى التطبيق
Go (Golang) هي لغة تشجع على بساطة الكود وسهولة قراءته. ومع ذلك، عندما يكبر المشروع، حتى الكود الأكثر إيجازًا يمكن أن يتحول إلى فوضى بدون بنية صحيحة. على المستوى المتقدم، يستخدم مطورو Go بنشاط أنماط التصميم المُكيَّفة مع خصائص اللغة: goroutines، channels، interfaces، و generics (منذ Go 1.18+).
في هذه المقالة، سنشرح 4 أنماط قوية ستساعدك على كتابة كود قابل للتوسع والاختبار وذو أداء عالٍ في Go. كل نمط مصحوب بمثال عملي.
1. نمط Pipeline لمعالجة البيانات المتدفقة
Pipeline هو أحد أكثر الأنماط شيوعًا في Go للعمل مع معالجة البيانات التسلسلية. يتناسب بشكل مثالي مع نموذج goroutines و channels. كل مرحلة معالجة تُنفذ في goroutine منفصلة، وتُنقل البيانات عبر channels.
متى يُستخدم: معالجة السجلات، تحويل البيانات، عمليات ETL، البث المباشر للفيديو.
مثال: خط أنابيب لتصفية وتحويل الأرقام.
package main
import "fmt"
// Stage 1: توليد الأرقامfunc generate(nums ...int) <-chan int { out := make(chan int) go func() { for _, n := range nums { out <- n } close(out) }() return out}
// Stage 2: الضرب في 2func multiply(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { out <- n * 2 } close(out) }() return out}
// Stage 3: التصفية (الأرقام الزوجية فقط)func filterEven(in <-chan int) <-chan int { out := make(chan int) go func() { for n := range in { if n%2 == 0 { out <- n } } close(out) }() return out}
func main() { // تجميع خط الأنابيب pipeline := filterEven(multiply(generate(1, 2, 3, 4, 5)))
for result := range pipeline { fmt.Println(result) // الإخراج: 4, 8 (الأرقام الزوجية فقط بعد الضرب) }}المزايا: معالجة متوازية طبيعية، استهلاك منخفض للذاكرة (البيانات لا تتراكم)، سهولة إضافة مراحل جديدة.
2. Fan-Out / Fan-In: توسيع نطاق المعالجة
هذا النمط هو تطور متقدم لـ Pipeline. Fan-Out (التفرع) يُشغل عدة goroutines لمعالجة البيانات من channel واحد بالتوازي. Fan-In (الدمج) يجمع النتائج من عدة channels في channel واحد.
متى يُستخدم: تحليل صفحات الويب، معالجة عدد كبير من الملفات، الطلبات المتوازية لواجهات API.
مثال: التحقق المتوازي من توفر عناوين URL.
package main
import ( "fmt" "net/http" "sync")
func worker(urls <-chan string, results chan<- string, wg *sync.WaitGroup) { defer wg.Done() for url := range urls { resp, err := http.Get(url) if err != nil { results <- fmt.Sprintf("خطأ: %s - %v", url, err) continue } resp.Body.Close() results <- fmt.Sprintf("موافق: %s - %d", url, resp.StatusCode) }}
func fanOutFanIn(urls []string, numWorkers int) []string { urlChan := make(chan string, len(urls)) resultChan := make(chan string, len(urls)) var wg sync.WaitGroup
// Fan-Out: تشغيل العمال for i := 0; i < numWorkers; i++ { wg.Add(1) go worker(urlChan, resultChan, &wg) }
// إرسال عناوين URL for _, url := range urls { urlChan <- url } close(urlChan)
// انتظار انتهاء جميع العمال wg.Wait() close(resultChan)
// Fan-In: جمع النتائج var results []string for res := range resultChan { results = append(results, res) } return results}
func main() { urls := []string{ "https://google.com", "https://github.com", "https://invalid-url", }
results := fanOutFanIn(urls, 3) for _, res := range results { fmt.Println(res) }}المزايا: تسريع المعالجة بشكل كبير، عزل الأخطاء (فشل worker واحد لا يؤثر على الباقي)، تحكم مرن في درجة التوازي.