ترقية الـ Method
جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 36 من 107.
تماماً كما يؤدي تضمين الـ struct إلى ترقية الحقول إلى الـ struct الخارجي، تقوم لغة Go أيضاً بترقية الأساليب (methods) من الأنواع المضمنة. وهذا يعني أنه يمكنك استدعاء الأساليب المعرفة في الـ struct المضمن مباشرة من الـ struct الخارجي.
type Engine struct {
Horsepower int
}
func (e Engine) Start() string {
return "Engine started"
}
type Car struct {
Model string
Engine // مضمن
}
بما أن Car تتضمن Engine، فإن الطريقة Start() يتم ترقيتها تلقائيًا:
func main() {
c := Car{
Model: "Sedan",
Engine: Engine{Horsepower: 200},
}
fmt.Println(c.Start()) // تم تشغيل المحرك
fmt.Println(c.Engine.Start()) // تعمل أيضًا
}
لهذه الترقية نتيجة مهمة بالنسبة للواجهات (interfaces). إذا كان النوع المضمن (embedded type) يحقق واجهة معينة، فإن النوع الخارجي يحققها تلقائياً أيضاً:
type Starter interface {
Start() string
}
func Ignite(s Starter) {
fmt.Println(s.Start())
}
func main() {
c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
Ignite(c) // Car يحقق Starter من خلال Engine
}
لا يقوم النوع Car بتنفيذ Starter بشكل صريح أبداً، ومع ذلك فإنه يستوفي الواجهة (interface) لأن Engine المضمن لديه الطريقة (method) المطلوبة. هذه هي الطريقة التي تحقق بها لغة Go إعادة استخدام السلوك دون الوراثة التقليدية.
التحدي
سهللنقم ببناء نظام مشغل موسيقى يوضح كيف يتم ترقية (promote) الأساليب (methods) من الأنواع المضمنة (embedded types) إلى النوع الخارجي، وكيف يتيح ذلك تحقيق الواجهات (interfaces) من خلال التركيب (composition).
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
audio.go: قم بإنشاء اللبنات الأساسية لمشغل الموسيقى الخاص بك:- هيكل
AudioPlayerمع حقلBrand(string) وطريقةPlay() stringتعيد[Brand] playing audio - واجهة
Playableتتطلب طريقةPlay() string - هيكل
Smartphoneمع حقلModelيتضمنAudioPlayer - هيكل
Tabletمع حقلModelيتضمنAudioPlayer
- هيكل
main.go: قم بإنشاء دالة تسمىStartPlaybackتقبل أيPlayableوتعيد نتيجة استدعاءPlay(). اقرأ معلومات الجهاز من الإدخال، وأنشئ كلاً من Smartphone و Tablet، وأثبت أن كلاهما يحقق واجهةPlayableمن خلالAudioPlayerالمضمن فيهما — على الرغم من أن أيًا من النوعين لا ينفذPlay()بشكل صريح بنفسه.
سيتم توفير المدخلات التالية:
- السطر 1: اسم طراز Smartphone
- السطر 2: العلامة التجارية للصوت في Smartphone
- السطر 3: اسم طراز Tablet
- السطر 4: العلامة التجارية للصوت في Tablet
لكل جهاز، اطبع طرازه متبوعًا بنتيجة تمريره إلى StartPlayback.
على سبيل المثال، إذا تم إعطاء iPhone 15، و Apple Audio، و iPad Pro، و Beats، يجب أن يكون مخرجك:
iPhone 15
Apple Audio playing audio
iPad Pro
Beats playing audioلاحظ كيف يمكن تمرير كل من Smartphone و Tablet إلى StartPlayback لأن طريقة Play() من AudioPlayer يتم ترقيتها تلقائيًا إلى كل نوع خارجي، مما يحقق واجهة Playable دون أي كود إضافي.
ورقة مرجعية
عندما تقوم بنية (struct) بتضمين نوع آخر، يتم ترقية الأساليب (methods) من النوع المضمن تلقائياً إلى البنية الخارجية:
type Engine struct {
Horsepower int
}
func (e Engine) Start() string {
return "Engine started"
}
type Car struct {
Model string
Engine // embedded
}
func main() {
c := Car{
Model: "Sedan",
Engine: Engine{Horsepower: 200},
}
fmt.Println(c.Start()) // Engine started
fmt.Println(c.Engine.Start()) // يعمل أيضاً
}
إذا كان النوع المضمن يستوفي واجهة (interface)، فإن النوع الخارجي يستوفيها تلقائياً أيضاً:
type Starter interface {
Start() string
}
func Ignite(s Starter) {
fmt.Println(s.Start())
}
func main() {
c := Car{Model: "Sedan", Engine: Engine{Horsepower: 200}}
Ignite(c) // Car تستوفي Starter من خلال Engine
}
يتيح ذلك إعادة استخدام السلوك من خلال التركيب (composition) بدون الوراثة التقليدية.
جرّب بنفسك
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: إنشاء دالة StartPlayback تقبل أي Playable
// وتعيد نتيجة استدعاء Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
// قراءة موديل الهاتف الذكي
scanner.Scan()
smartphoneModel := scanner.Text()
// قراءة العلامة التجارية للصوت في الهاتف الذكي
scanner.Scan()
smartphoneBrand := scanner.Text()
// قراءة موديل الجهاز اللوحي
scanner.Scan()
tabletModel := scanner.Text()
// قراءة العلامة التجارية للصوت في الجهاز اللوحي
scanner.Scan()
tabletBrand := scanner.Text()
// TODO: إنشاء Smartphone مع AudioPlayer مدمج
// TODO: إنشاء Tablet مع AudioPlayer مدمج
// TODO: طباعة موديل الهاتف الذكي، ثم استدعاء StartPlayback مع الهاتف الذكي
// TODO: طباعة موديل الجهاز اللوحي، ثم استدعاء StartPlayback مع الجهاز اللوحي
_ = smartphoneModel
_ = smartphoneBrand
_ = tabletModel
_ = tabletBrand
fmt.Println("TODO: Complete the implementation")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP في Go
الملفات الخارجيةمساحة العمل والـ Modules في Goالـ Packages والـ Importsالأسماء المصدرة مقابل غير المصدرةمقدمة إلى الـ OOP في Goالـ Structs كـ Classesتعريف الـ Methods في الـ Structsالـ Pointer Receivers مقابل الـ Value Receiversتهيئة الـ Structدوال الـ Constructorمراجعة - آلة حاسبة بسيطة4الواجهات
مقدمة في الواجهاتالتنفيذ الضمنيالواجهة كعقدالواجهة الفارغة (any)تأكيد النوع (Type Assertion)تبديل النوع (Type Switch)تركيب الواجهاتواجهات Stringer و Errorمراجعة - حاسبة الأشكال7التغليف
الحقول المصدرة وغير المصدرةالتغليف على مستوى الحزمةدوال الـ Getter والـ Setterإخفاء المعلومات في Goملخص - سجلات الطلاب10الأنواع العامة (Go 1.18+)
مقدمة في الأنواع العامةمعاملات الأنواعقيود الأنواعالـ Structs العامةحل بديل للـ Methods العامةملخص - المجموعات العامة13أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Abstract Factoryنمط Observerنمط Strategy2تعمق في الأنواع و Structs
الأنواع الأساسية والمركبةتعريفات الأنواع المخصصةStruct TagsStructs مجهولةStructs متداخلةالقيم الصفرية والافتراضيةمراجعة - دفتر العناوين5التركيب بدلاً من الوراثة
لماذا لا تدعم Go الوراثةأساسيات تضمين الـ Structترقية الـ Methodتضمين عدة Structsالتضمين مقابل التجميعحجب الـ Methods المضمنةملخص - الهيكل الهرمي للموظفين8معالجة الأخطاء و OOP
واجهة errorأنواع الأخطاء المخصصةتغليف الأخطاء (fmt.Errorf)أخطاء Sentinelerrors.Is() و errors.As()Panic و Defer و Recoverملخص - File Parser11المكتبة القياسية والبرمجة كائنية التوجه (OOP)
io.Reader و io.Writerواجهة sort.Interfaceواجهة fmt.Stringerencoding/json مع Structsواجهة http.Handlerمراجعة - نماذج REST API14أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبMiddleware كنمط مزين3المؤشرات والذاكرة
أساسيات المؤشرات في Goالمؤشرات إلى الـ Structsالتمرير بالقيمة مقابل التمرير بالمرجعدالة ()newGarbage Collection في Goملخص - بناء Linked List6تعدد الأشكال في Go
تعدد الأشكال عبر InterfacesDuck Typing في Goقواعد استيفاء الـ Interfaceمجموعات متعددة الأشكالحقن التبعيةمراجعة - معالج الدفع9التزامن والبرمجة كائنية التوجه (OOP)
أساسيات الـ Goroutinesالقنوات (Channels) والاتصالالقنوات المخزنة (Buffered) مقابل غير المخزنةجملة Selectsync.Mutex و sync.RWMutexsync.WaitGroupتصميم الـ Structs الآمنة للخيوط (Thread-Safe)مراجعة - Worker Pool