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

نمط Strategy

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

يتيح لك نمط الاستراتيجية تعريف عائلة من الخوارزميات، وتغليف كل واحدة منها، وجعلها قابلة للتبديل أثناء التشغيل. وعلى خلاف Observer، حيث تتفاعل كائنات متعددة مع حدث واحد، يتيح Strategy لكائن واحد التبديل بين سلوكيات مختلفة بشكل ديناميكي.

في Go، نطبّق Strategy من خلال Define واجهة للخوارزمية وحقن Implementations مختلفة في بنية context:

type PaymentStrategy interface {
    Pay(amount float64) string
}

type CreditCard struct{}
func (c CreditCard) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via Credit Card", amount)
}

type PayPal struct{}
func (p PayPal) Pay(amount float64) string {
    return fmt.Sprintf("Paid %.2f via PayPal", amount)
}

تحتفظ بنية context بمرجع إلى واجهة الاستراتيجية، مما يسمح بتبديل الخوارزمية دون تغيير كود context:

type Checkout struct {
    strategy PaymentStrategy
}

func (c *Checkout) SetStrategy(s PaymentStrategy) {
    c.strategy = s
}

func (c *Checkout) ProcessPayment(amount float64) string {
    return c.strategy.Pay(amount)
}

يمكنك الآن تغيير طريقة الدفع أثناء التشغيل:

checkout := &Checkout{}

checkout.SetStrategy(CreditCard{})
fmt.Println(checkout.ProcessPayment(100.00))  // تم دفع 100.00 عبر بطاقة الائتمان

checkout.SetStrategy(PayPal{})
fmt.Println(checkout.ProcessPayment(50.00))   // تم دفع 50.00 عبر PayPal

يُعدّ Strategy مثاليًا عندما تكون لديك طرق متعددة لتنفيذ operation وتحتاج إلى اختيار واحدة بناءً على إدخال المستخدم أو التكوين أو شروط وقت التشغيل. تشمل حالات الاستخدام الشائعة خوارزميات الفرز وطرق الضغط وقواعد التحقق.

challenge icon

التحدي

سهل

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

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

  • formatter.go: Define واجهة الاستراتيجية واستراتيجيات التنسيق الملموسة.

    أنشئ واجهة TextFormatter تحتوي على طريقة Format(text string) string تحوّل النص وفقًا لقواعد الاستراتيجية.

    Implement ثلاث استراتيجيات للتنسيق:

    • UppercaseFormatter: تحوّل النص إلى أحرف كبيرة بالكامل
    • SnakeCaseFormatter: تحوّل المسافات إلى شرطات سفلية وتجعل النص بأحرف صغيرة
    • TitleFormatter: تجعل الحرف الأول من كل كلمة كبيرًا (تُفصل الكلمات بمسافات)
  • processor.go: Create بنية السياق التي تستخدم استراتيجية التنسيق.

    أنشئ بنية TextProcessor التي holds استراتيجية TextFormatter. أضف الطريقتين التاليتين:

    • SetFormatter(f TextFormatter) لتغيير استراتيجية التنسيق active
    • Process(text string) string التي تطبّق المنسّق current على النص

    أنشئ أيضًا مُنشئًا NewTextProcessor() يعيد معالجًا من دون منسّق initial معيّن.

  • main.go: اعرض تبديل الاستراتيجيات أثناء التشغيل.

    اقرأ جزءًا من النص، ثم اقرأ count من عمليات التنسيق. لكل operation، اقرأ نوع التنسيق (upper أو snake أو title)، وعيّن المنسّق appropriate إلى معالجك، ثم عالج النص الأصلي واطبع النتيجة.

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

  • السطر 1: النص المطلوب تنسيقه
  • السطر 2: عدد عمليات التنسيق
  • الأسطر التالية: نوع التنسيق لكل عملية

على سبيل المثال، عند تقديم:

hello world today
3
upper
snake
title

يجب أن يكون إخراجك:

HELLO WORLD TODAY
hello_world_today
Hello World Today

وعند تقديم:

Go Programming Language
2
snake
upper

يجب أن يكون إخراجك:

go_programming_language
GO PROGRAMMING LANGUAGE

وعند تقديم:

design patterns are useful
1
title

يجب أن يكون إخراجك:

Design Patterns Are Useful

لاحظ كيف تنتج TextProcessor نفسها مخرجات مختلفة تمامًا بمجرد تبديل استراتيجية المنسّق. لا يعرف المعالج أي منسّق محدد يستخدمه، ولا يهتم بذلك. إنه ببساطة delegates إلى الاستراتيجية التي تم تعيينها حاليًا!

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
	"strconv"
	"strings"
)

func main() {
	reader := bufio.NewReader(os.Stdin)
	
	// اقرأ النص المراد تنسيقه
	text, _ := reader.ReadString('\n')
	text = strings.TrimSpace(text)
	
	// اقرأ عدد العمليات
	countStr, _ := reader.ReadString('\n')
	count, _ := strconv.Atoi(strings.TrimSpace(countStr))
	
	// أنشئ معالج نصوص جديد
	processor := NewTextProcessor()
	
	// عالج كل عملية تنسيق
	for i := 0; i < count; i++ {
		formatType, _ := reader.ReadString('\n')
		formatType = strings.TrimSpace(formatType)
		
		// TODO: بناءً على formatType ("upper", "snake", أو "title")،
		// عيّن المنسّق المناسب على المعالج
		// واطبع النص المُعالَج
		
	}
}
quiz iconاختبر نفسك

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

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

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