ترقية الـ Method
جزء من قسم البرمجة كائنية التوجه في رحلة GO على Coddy. الدرس 36 من 107.
تمامًا كما يعمل تضمين البُنى على ترقية الحقول إلى البنية الخارجية، تعمل Go أيضًا على ترقية الأساليب من الأنواع المضمّنة. وهذا يعني أنه يمكنك استدعاء الأساليب المعرّفة على البنية المضمّنة مباشرةً على البنية الخارجية.
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()) // يعمل أيضاً
}
لهذا الترويج نتيجة مهمة بالنسبة إلى الواجهات. إذا كان النوع المضمَّن يحقق واجهة، فإن النوع الخارجي يحققها تلقائيًا أيضًا:
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 بشكل صريح مطلقًا، ومع ذلك فهو يستوفي الواجهة لأن Engine المضمَّن فيه يملك الطريقة المطلوبة. هذه هي الطريقة التي تحقق بها Go إعادة استخدام السلوك من دون وراثة تقليدية.
التحدي
سهللنَبْنِ نظامَ مشغّل موسيقى يوضّح كيفية ترقية الأساليب من الأنواع المُضمَّنة إلى النوع الخارجي، وكيف يتيح ذلك استيفاء الواجهة من خلال التركيب.
ستنظّم شيفرتك عبر ملفَّين:
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 دون أي شيفرة إضافية.
جرّب بنفسك
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")
}
يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس البرمجة كائنية التوجه
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تدرّب بنفسك: مترجم Go عبر الإنترنت