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

تركيب الواجهات

جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 31 من 107.

تتيح لك لغة Go بناء واجهات أكبر عن طريق تركيب واجهات أصغر. فبدلاً من تعريف واجهة واحدة كبيرة تحتوي على العديد من الـ methods، يمكنك تضمين واجهات موجودة مسبقاً داخل تعريف واجهة جديدة.

type Reader interface {
    Read() string
}

type Writer interface {
    Write(data string)
}

// ReadWriter يجمع بين كلتا الواجهتين
type ReadWriter interface {
    Reader
    Writer
}

تتطلب واجهة ReadWriter الآن كلاً من الطريقتين Read() و Write(). أي نوع يقوم بتنفيذ كلتا الطريقتين يستوفي ReadWriter، بالإضافة إلى Reader و Writer بشكل فردي.

type File struct {
    Name string
}

func (f File) Read() string       { return "file content" }
func (f File) Write(data string)  { fmt.Println("Writing:", data) }

func Process(rw ReadWriter) {
    content := rw.Read()
    rw.Write(content)
}

func main() {
    f := File{Name: "data.txt"}
    Process(f)  // File يستوفي ReadWriter
}

هذا النهج في التركيب يحافظ على الواجهات صغيرة ومركزة. يمكنك المزج والمطابقة بينها حسب الحاجة، مما يؤدي إلى إنشاء عقود دقيقة لوظائفك. تستخدم مكتبة Go القياسية هذا النمط على نطاق واسع، مثل io.ReadWriter الذي يجمع بين io.Reader و io.Writer.

challenge icon

التحدي

سهل

لنقم ببناء نظام مشغل وسائط يوضح تكوين الواجهات (interface composition). ستقوم بإنشاء واجهات صغيرة ومحددة، ثم دمجها في واجهة مركبة أكثر قوة يمكن لنوع واحد تلبيتها.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • media.go: حدد ثلاث واجهات وهيكل (struct) يقوم بتنفيذها جميعاً:
    • واجهة Player مع تابع Play() string
    • واجهة Recorder مع تابع Record(content string) string
    • واجهة MediaDevice التي تجمع بين كل من Player و Recorder
    • هيكل SmartDevice مع حقل Name ينفذ جميع التوابع المطلوبة
  • main.go: أنشئ دوال توضح كيف يمكن استخدام نفس الـ SmartDevice من خلال أنواع واجهات مختلفة. اكتب ثلاث دوال:
    • UsePlayer التي تقبل Player وتستدعي تابع Play الخاص به
    • UseRecorder التي تقبل Recorder وسلسلة نصية للمحتوى، ثم تستدعي Record
    • UseMediaDevice التي تقبل MediaDevice وسلسلة نصية للمحتوى، ثم تستدعي كلاً من Record و Play
    اقرأ اسم الجهاز والمحتوى من الإدخال، وأنشئ SmartDevice، ووضح استخدامه من خلال جميع أنواع الواجهات الثلاثة.

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

  • السطر 1: اسم الجهاز
  • السطر 2: المحتوى المراد تسجيله

يجب أن تعيد التوابع الخاصة بك سلاسل نصية بهذه التنسيقات:

  • Play(): [Name] is playing
  • Record(content): [Name] recorded: [content]

على سبيل المثال، إذا تم إعطاء MyPhone و voice memo، يجب أن يكون الناتج:

MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playing

يوضح أول سطرين الجهاز المستخدم من خلال الواجهات الفردية (Player و Recorder). يوضح السطران الأخيران استخدامه من خلال واجهة MediaDevice المركبة، والتي تتطلب كلتا القدرتين. لاحظ كيف أن SmartDevice الخاص بك يلبي جميع الواجهات الثلاث لأنه يمتلك كلا التابعين المطلوبين.

ورقة مرجعية

تسمح لك لغة Go ببناء واجهات أكبر من خلال تركيب واجهات أصغر عن طريق تضمين واجهات موجودة داخل تعريف واجهة جديدة:

type Reader interface {
    Read() string
}

type Writer interface {
    Write(data string)
}

// ReadWriter يجمع بين كلتا الواجهتين
type ReadWriter interface {
    Reader
    Writer
}

أي نوع يقوم بتنفيذ جميع الدوال من الواجهات المضمنة يحقق الواجهة المركبة:

type File struct {
    Name string
}

func (f File) Read() string       { return "file content" }
func (f File) Write(data string)  { fmt.Println("Writing:", data) }

func Process(rw ReadWriter) {
    content := rw.Read()
    rw.Write(content)
}

func main() {
    f := File{Name: "data.txt"}
    Process(f)  // File يحقق ReadWriter
}

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

جرّب بنفسك

package main

import (
	"bufio"
	"fmt"
	"os"
)

// TODO: قم بتنفيذ UsePlayer التي تقبل Player وتستدعي طريقة Play الخاصة بها
// يجب أن تطبع نتيجة Play()

// TODO: قم بتنفيذ UseRecorder التي تقبل Recorder وسلسلة نصية content
// يجب أن تطبع نتيجة Record(content)

// TODO: قم بتنفيذ UseMediaDevice التي تقبل MediaDevice وسلسلة نصية content
// يجب أن تطبع نتيجة Record(content) ثم Play()

func main() {
	scanner := bufio.NewScanner(os.Stdin)
	
	scanner.Scan()
	deviceName := scanner.Text()
	
	scanner.Scan()
	content := scanner.Text()
	
	// TODO: قم بإنشاء SmartDevice بالاسم المعطى
	
	// TODO: استخدم الجهاز من خلال واجهة Player
	
	// TODO: استخدم الجهاز من خلال واجهة Recorder
	
	// TODO: استخدم الجهاز من خلال واجهة MediaDevice
	
	_ = deviceName
	_ = content
	fmt.Println("Implement the solution")
}
quiz iconاختبر نفسك

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

جميع دروس Object Oriented Programming