Menu
CoddyTech

تضمين عدة Structs

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

تتيح لك Go تضمين عدة بُنى داخل بنية واحدة، ودمج سلوكيات من مصادر مختلفة. يشبه هذا الوراثة المتعددة في لغات أخرى، لكنه يعتمد على أسلوب التركيب في Go.

type Logger struct{}

func (l Logger) Log(msg string) string {
    return "LOG: " + msg
}

type Notifier struct{}

func (n Notifier) Notify(msg string) string {
    return "NOTIFY: " + msg
}

type Service struct {
    Name string
    Logger
    Notifier
}

أصبح بإمكان البنية Service الآن الوصول إلى الأساليب من كلا النوعين المضمَّنين:

func main() {
    s := Service{Name: "OrderService"}
    fmt.Println(s.Log("started"))      // LOG: بدأ
    fmt.Println(s.Notify("new order")) // NOTIFY: طلب جديد
}

عند تضمين عدة بُنى، قد يحدث تعارض في التسمية إذا كان لنوعين مُضمَّنين طرائق بالاسم نفسه. لا يحل Go هذا الالتباس تلقائيًا:

type A struct{}
func (A) Greet() string { return "Hello from A" }

type B struct{}
func (B) Greet() string { return "Hello from B" }

type Combined struct {
    A
    B
}

func main() {
    c := Combined{}
    // c.Greet() - خطأ في الترجمة البرمجية: محدِّد ملتبس
    fmt.Println(c.A.Greet())  // مرحبًا من A
    fmt.Println(c.B.Greet())  // مرحبًا من B
}

عند حدوث تعارضات، يجب أن تحدد صراحةً طريقة النوع المضمَّن التي تريد استدعاءها باستخدام اسم النوع كمُحدِّد.

challenge icon

التحدي

سهل

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

ستنظم التعليمات البرمجية في ثلاثة ملفات:

  • controllers.go: أنشئ بنيتي وحدات تحكم مستقلتين توفران إمكانات مختلفة:
    • بنية LightController تحتوي على حقل Brightness (من النوع int) وطريقة SetLight(level int) string تعيد Light set to [level]%
    • بنية AudioController تحتوي على حقل Volume (من النوع int) وطريقة SetVolume(level int) string تعيد Volume set to [level]%
    ينبغي أن تحتوي كلتا وحدتي التحكم أيضًا على طريقة Status() string. ينشأ عن ذلك تعارض في التسمية سيتعين عليك معالجته. ينبغي أن تعيد LightController.Status() القيمة Brightness: [Brightness]%، وأن تعيد AudioController.Status() القيمة Volume: [Volume]%.
  • device.go: أنشئ بنية SmartDevice تحتوي على حقل Name وتضمّن كلًا من LightController وAudioController. أضف طريقة باسم FullStatus() string تعيد اسم الجهاز مع حالتي وحدتي التحكم، مع حل الالتباس باستدعاء طريقة Status() الخاصة بكل نوع مضمن صراحةً.
  • main.go: اقرأ إعدادات الجهاز من الإدخال، وأنشئ SmartDevice، واستخدم الطرق المروّجة لضبط مستويي الإضاءة والصوت، ثم اعرض الحالة الكاملة.

ستُعطى المدخلات التالية:

  • السطر 1: اسم الجهاز
  • السطر 2: مستوى السطوع الأولي (عدد صحيح)
  • السطر 3: مستوى الصوت الأولي (عدد صحيح)
  • السطر 4: مستوى السطوع الجديد المراد ضبطه (عدد صحيح)
  • السطر 5: مستوى الصوت الجديد المراد ضبطه (عدد صحيح)

ينبغي أن تعيد طريقة FullStatus() القيمة التالية:

[Name] - [LightController.Status()], [AudioController.Status()]

اطبع ناتج استدعاء SetLight وSetVolume (وهما مروّجان من النوعين المضمّنين)، ثم اطبع الحالة الكاملة.

على سبيل المثال، عند إعطاء Lounge و50 و30 و75 و60، ينبغي أن يكون الناتج:

Light set to 75%
Volume set to 60%
Lounge - Brightness: 75%, Volume: 60%

لاحظ أن SetLight وSetVolume متاحتان مباشرةً على SmartDevice من خلال ترويج الطرق، لكن Status() يتطلب تحديدًا صريحًا لأن كلا النوعين المضمّنين يحتويان على هذه الطريقة.

جرّب بنفسك

package main

import (
	"fmt"
)

func main() {
	// اقرأ المدخلات
	var name string
	fmt.Scanln(&name)

	var initialBrightness int
	fmt.Scanln(&initialBrightness)

	var initialVolume int
	fmt.Scanln(&initialVolume)

	var newBrightness int
	fmt.Scanln(&newBrightness)

	var newVolume int
	fmt.Scanln(&newVolume)

	// TODO: أنشئ SmartDevice بالاسم والقيم الأولية المحددة

	// TODO: استخدم الطريقة SetLight المضمّنة واطبع النتيجة

	// TODO: استخدم الطريقة SetVolume المضمّنة واطبع النتيجة

	// TODO: اطبع الحالة الكاملة باستخدام الطريقة FullStatus()
}
quiz iconاختبر نفسك

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

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

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