منصة تعليم إلكتروني
جزء من قسم Object Oriented Programming في رحلة GO على Coddy — الدرس 105 من 107.
التحدي
سهللنقم ببناء منصة تعليم إلكتروني تدير الدورات التدريبية، والطلاب، وتتبع تقدم التعلم! ستجمع بين الهياكل (structs)، والواجهات (interfaces)، والتركيب (composition)، وتعدد الأشكال (polymorphism) لإنشاء نظام متماسك حيث يمكن للطلاب التسجيل في الدورات وإكمال الدروس.
ستقوم بتنظيم الكود الخاص بك عبر خمسة ملفات:
lesson.go: قم بتعريف هيكلLessonيمثل وحدات تعليمية فردية. كل درس لهID، وTitle، وDuration(بالدقائق). قم بتضمين منشئNewLessonيعيد مؤشراً إلى Lesson.course.go: قم بإنشاء هيكلCourseيحتوي علىID، وTitle، وInstructor، وشريحة (slice) من مؤشرات*Lesson. قم بتضمين منشئNewCourseوتابعAddLesson. قم أيضاً بتنفيذ تابعTotalDuration() intيعيد مجموع مدد جميع الدروس في الدورة.student.go: قم بتعريف هيكلStudentمع حقولID، وName، وEmail. قم بتضمين منشئNewStudent.enrollment.go: هذا هو المكان الذي يحدث فيه سحر تتبع التقدم. قم بإنشاء هيكلEnrollmentيربط الطالب بدورة تدريبية ويتتبع الدروس التي أكملها. يجب أن يحتوي على:- مؤشر إلى
Student - مؤشر إلى
Course - خريطة
CompletedLessons(معرف الدرس إلى قيمة منطقية boolean)
قم بتعريف واجهة
Progressableمع تابعProgress() float64يعيد نسبة مئوية (من 0.0 إلى 100.0).قم بتنفيذ هذه التوابع على Enrollment:
NewEnrollment(student *Student, course *Course) *Enrollment— منشئ يقوم بتهيئة خريطة دروس مكتملة فارغة.CompleteLesson(lessonID string) string— يحدد الدرس كمكتمل. يعيد"lesson not found"إذا لم يكن الدرس موجوداً في الدورة، أو"already completed"إذا كان قد اكتمل بالفعل، أو"completed"عند النجاح.Progress() float64— يعيد النسبة المئوية للدروس المكتملة (المكتملة/الإجمالي * 100)، أو 0.0 إذا كانت الدورة لا تحتوي على دروس.
- مؤشر إلى
main.go: قم ببناء منصتك ومعالجة عمليات التسجيل.اقرأ معرف الدورة، وعنوانها، والمحاضر. ثم اقرأ عدد الدروس ومعرف كل درس وعنوانه ومدته. اقرأ معرف الطالب واسمه وبريده الإلكتروني. أنشئ تسجيلاً (enrollment) يربط الطالب بالدورة.
ثم اقرأ عدد العمليات. كل عملية هي إما
"complete [lessonID]"أو"progress". بالنسبة لعمليات الإكمال، اطبع رسالة النتيجة. بالنسبة لعمليات التقدم، اطبع التقدم منسقاً إلى منزلة عشرية واحدة متبوعاً بعلامة النسبة المئوية.
سيتم توفير المدخلات التالية:
- معرف الدورة، العنوان، المحاضر (3 أسطر)
- عدد الدروس، ثم معرف كل درس، العنوان، المدة (3 أسطر لكل درس)
- معرف الطالب، الاسم، البريد الإلكتروني (3 أسطر)
- عدد العمليات، ثم كل عملية (سطر واحد لكل منها)
على سبيل المثال، إذا أعطيت:
C001
Go Fundamentals
Jane Smith
3
L001
Variables
30
L002
Functions
45
L003
Structs
60
S001
Alice
alice@learn.com
5
progress
complete L001
progress
complete L001
complete L002يجب أن يكون مخرجك:
0.0%
completed
33.3%
already completed
completedوإذا أعطيت:
C100
Python Basics
Bob Teacher
2
L100
Intro
20
L101
Loops
40
S100
Charlie
charlie@edu.com
4
complete L999
complete L100
complete L101
progressيجب أن يكون مخرجك:
lesson not found
completed
completed
100.0%لاحظ كيف يستخدم هيكل Enrollment التركيب لربط الطلاب والدورات معاً، بينما تسمح واجهة Progressable لأي نوع بالإبلاغ عن حالة اكتماله. هذا التصميم يجعل من السهل التوسع — يمكنك إضافة تتبع التقدم للدروس الفردية أو مسارات التعلم الكاملة باستخدام نفس الواجهة!
جرّب بنفسك
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// دالة مساعدة لقراءة سطر
readLine := func() string {
scanner.Scan()
return strings.TrimSpace(scanner.Text())
}
// قراءة معلومات الدورة
courseID := readLine()
courseTitle := readLine()
courseInstructor := readLine()
// TODO: إنشاء الدورة باستخدام NewCourse
_ = courseID
_ = courseTitle
_ = courseInstructor
// قراءة عدد الدروس
numLessons, _ := strconv.Atoi(readLine())
// TODO: قراءة كل درس وإضافته إلى الدورة
for i := 0; i < numLessons; i++ {
lessonID := readLine()
lessonTitle := readLine()
lessonDuration, _ := strconv.Atoi(readLine())
// TODO: إنشاء الدرس وإضافته إلى الدورة
_ = lessonID
_ = lessonTitle
_ = lessonDuration
}
// قراءة معلومات الطالب
studentID := readLine()
studentName := readLine()
studentEmail := readLine()
// TODO: إنشاء الطالب باستخدام NewStudent
_ = studentID
_ = studentName
_ = studentEmail
// TODO: إنشاء تسجيل يربط الطالب بالدورة
// قراءة عدد العمليات
numOps, _ := strconv.Atoi(readLine())
// معالجة كل عملية
for i := 0; i < numOps; i++ {
operation := readLine()
if operation == "progress" {
// TODO: استدعاء Progress() والطباعة بالتنسيق "%.1f%%"
fmt.Println("0.0%") // استبدله بالتقدم الفعلي
} else if strings.HasPrefix(operation, "complete ") {
lessonID := strings.TrimPrefix(operation, "complete ")
// TODO: استدعاء CompleteLesson وطباعة النتيجة
_ = lessonID
fmt.Println("") // استبدله بالنتيجة الفعلية
}
}
}
جميع دروس 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