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

تعدد الأشكال عبر Interfaces

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

يسمح polymorphism بالتعامل مع أنواع مختلفة بطريقة موحّدة من خلال واجهة مشتركة. في Go، يتحقق ذلك بالكامل من خلال الواجهات، من دون التوريث أو التسلسلات الهرمية للفئات.

عندما تقبل function نوع interface كمعامل، يمكن تمرير أي نوع ملموس يطبّق ذلك الـinterface. لا تحتاج function إلى معرفة النوع المحدد. فهي تهتم فقط بالسلوك الذي يحدده الـinterface:

type Speaker interface {
    Speak() string
}

type Dog struct{ Name string }
func (d Dog) Speak() string { return "Woof!" }

type Cat struct{ Name string }
func (c Cat) Speak() string { return "Meow!" }

func MakeSound(s Speaker) {
    fmt.Println(s.Speak())
}

الآن تعمل MakeSound مع أي نوع لديه طريقة Speak():

func main() {
    dog := Dog{Name: "Rex"}
    cat := Cat{Name: "Whiskers"}
    
    MakeSound(dog)  // ووف!
    MakeSound(cat)  // مياو!
}

ينتج استدعاء function نفسه سلوكًا مختلفًا اعتمادًا على النوع الفعلي المُمرَّر. هذا هو polymorphism أثناء العمل. تتم كتابة function MakeSound مرة واحدة، لكنها تعمل مع عدد غير محدود من الأنواع، ما دامت تستوفي الواجهة Speaker.

يحافظ هذا النهج على مرونة شفرتك وقابليتها للتوسّع. لا تتطلب إضافة نوع جديد يتحدث أي تغييرات في functions الحالية؛ ما عليك سوى تنفيذ interface، وسيعمل تلقائيًا.

challenge icon

التحدي

سهل

لنَبْنِ نظامًا لوصف المركبات يوضّح مفهوم polymorphism عمليًا. ستنشئ أنواعًا مختلفة من المركبات تشترك جميعها في سلوك common من خلال interface، ثم تكتب function واحدة تعمل مع any مركبة.

ستنظّم code الخاص بك عبر ملفين:

  • vehicles.go: عرّف interface باسم Describer يتطلب method باسم Describe() string. ثم أنشئ ثلاثة أنواع من المركبات، يطبّق كل منها هذا interface بطريقته الخاصة:
    • Car مع fields باسمَي Brand وModel. تُعيد Describe() القيمة Car: [Brand] [Model]
    • Motorcycle مع fields باسمَي Brand وEngineCC (من النوع int). تُعيد Describe() القيمة Motorcycle: [Brand] [EngineCC]cc
    • Bicycle مع field باسم Type (مثل "Mountain" أو "Road"). تُعيد Describe() القيمة Bicycle: [Type]
  • main.go: أنشئ function باسم PrintDescription تقبل أي Describer وتطبع نتيجة استدعاء Describe(). اقرأ تفاصيل المركبات من input، وأنشئ واحدة من كل نوع من أنواع المركبات، ومرّر كل واحدة منها إلى PrintDescription لإظهار أن function نفسها تعمل مع الأنواع الثلاثة المختلفة.

سيتم توفير input التالي:

  • السطر 1: Brand الخاص بـ Car
  • السطر 2: Model الخاص بـ Car
  • السطر 3: Brand الخاص بـ Motorcycle
  • السطر 4: Engine CC الخاص بـ Motorcycle (عدد صحيح)
  • السطر 5: Type الخاص بـ Bicycle

على سبيل المثال، عند إعطاء Toyota وCamry وHonda و600 وMountain، يجب أن يكون output الخاص بك:

Car: Toyota Camry
Motorcycle: Honda 600cc
Bicycle: Mountain

لاحظ أن PrintDescription لا تحتاج إلى معرفة ما إذا كانت تتلقى Car أو Motorcycle أو Bicycle. فهي تستدعي ببساطة Describe()، ويستجيب كل نوع بإخراجه الفريد الخاص به. هذا هو polymorphism: function واحدة، وسلوكيات متعددة.

جرّب بنفسك

package main

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

// TODO: أنشئ دالة تسمى PrintDescription تقبل أي Describer
// وتطبع نتيجة استدعاء Describe()

func main() {
	reader := bufio.NewReader(os.Stdin)

	// اقرأ تفاصيل السيارة
	carBrand, _ := reader.ReadString('\n')
	carBrand = strings.TrimSpace(carBrand)
	carModel, _ := reader.ReadString('\n')
	carModel = strings.TrimSpace(carModel)

	// اقرأ تفاصيل الدراجة النارية
	motoBrand, _ := reader.ReadString('\n')
	motoBrand = strings.TrimSpace(motoBrand)
	motoEngineStr, _ := reader.ReadString('\n')
	motoEngineStr = strings.TrimSpace(motoEngineStr)
	motoEngine, _ := strconv.Atoi(motoEngineStr)

	// اقرأ تفاصيل الدراجة
	bicycleType, _ := reader.ReadString('\n')
	bicycleType = strings.TrimSpace(bicycleType)

	// TODO: أنشئ Car و Motorcycle و Bicycle باستخدام قيم الإدخال

	// TODO: استدعِ PrintDescription لكل مركبة لإظهار تعدد الأشكال
	fmt.Println("TODO: Print vehicle descriptions")
}
quiz iconاختبر نفسك

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

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

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