Платформа онлайн-обучения
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy — урок 105 из 107.
Задание
ЛегкоДавайте создадим платформу электронного обучения, которая управляет курсами, студентами и отслеживает прогресс обучения! Вы объедините структуры, интерфейсы, композицию и полиморфизм для создания целостной системы, в которой студенты могут записываться на курсы и проходить уроки.
Вы организуете свой код в пяти файлах:
lesson.go: Определите структуруLesson, представляющую отдельные учебные единицы. Каждый урок имеетID,TitleиDuration(в минутах). Включите конструкторNewLesson, который возвращает указатель на Lesson.course.go: Создайте структуруCourse, которая содержитID,Title,Instructorи слайс указателей*Lesson. Включите конструкторNewCourseи методAddLesson. Также реализуйте методTotalDuration() int, который возвращает сумму длительностей всех уроков в курсе.student.go: Определите структуруStudentс полямиID,NameиEmail. Включите конструкторNewStudent.enrollment.go: Здесь происходит магия отслеживания прогресса. Создайте структуруEnrollment, которая связывает студента с курсом и отслеживает, какие уроки он завершил. Она должна иметь:- Указатель на
Student - Указатель на
Course - Карту
CompletedLessons(ID урока в логическое значение)
Определите интерфейс
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: Создайте свою платформу и обработайте операции по зачислению.Считайте ID курса, название и инструктора. Затем считайте количество уроков и ID, название и длительность каждого урока. Считайте ID студента, имя и email. Создайте запись о зачислении (enrollment), связывающую студента с курсом.
Затем считайте количество операций. Каждая операция — это либо
"complete [lessonID]", либо"progress". Для операций complete выведите ответное сообщение. Для операций progress выведите прогресс, отформатированный до одного знака после запятой, за которым следует знак процента.
Будут предоставлены следующие входные данные:
- ID курса, Название, Инструктор (3 строки)
- Количество уроков, затем ID, Название, Длительность каждого урока (по 3 строки на каждый)
- ID студента, Имя, Email (3 строки)
- Количество операций, затем каждая операция (по 1 строке на каждую)
Например, при вводе:
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: Создать регистрацию (enrollment), связывающую студента с курсом
// Чтение количества операций
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("") // Заменить на фактический результат
}
}
}
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП в Go
Внешние файлыРабочее пространство и модули GoПакеты и импортыЭкспортируемые и неэкспортируемые именаВведение в ООП в GoСтруктуры как классыОпределение методов структурПолучатели-указатели и получатели-значенияИнициализация структурФункции-конструкторыИтоги — Простой калькулятор4Интерфейсы
Введение в интерфейсыНеявная реализацияИнтерфейс как контрактПустой интерфейс (any)Утверждение типаПереключатель типовКомпозиция интерфейсовИнтерфейсы Stringer и ErrorПовторение: Калькулятор фигур7Инкапсуляция
Экспортируемые и неэкспортируемые поляИнкапсуляция на уровне пакетовГеттеры и сеттерыСокрытие информации в GoИтоги — Записи о студентах10Обобщения (Generics) (Go 1.18+)
Введение в GenericsПараметры типовОграничения типовОбобщенные структурыОбходной путь для обобщенных методовИтоги — Обобщенная коллекция13Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн Abstract FactoryПаттерн ObserverПаттерн Strategy2Глубокое погружение в типы и структуры
Базовые и составные типыОпределение пользовательских типовТеги структурАнонимные структурыВложенные структурыНулевые значения и значения по умолчаниюПовторение — Контактная книга5Композиция вместо наследования
Почему в Go нет наследованияОсновы встраивания структурПродвижение методовВстраивание нескольких структурВстраивание против агрегацииЗатенение встроенных методовИтоги — Иерархия сотрудников8Обработка ошибок и ООП
Интерфейс errorПользовательские типы ошибокОбертывание ошибок (fmt.Errorf)Sentinel-ошибкиerrors.Is() и errors.As()Panic, Defer и RecoverИтоги — Парсер файлов11Стандартная библиотека и ООП
io.Reader и io.Writersort.InterfaceИнтерфейс fmt.Stringerencoding/json со структурамиИнтерфейс http.HandlerПовторение: модели REST API14Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикMiddleware как Декоратор3Указатели и память
Основы указателей в GoУказатели на структурыПередача по значению и по ссылкеФункция new()Сборка мусора в GoПовторение: Конструктор связного списка6Полиморфизм в Go
Полиморфизм через интерфейсыУтиная типизация в GoПравила реализации интерфейсовПолиморфные коллекцииВнедрение зависимостейИтоги — Обработчик платежей9Конкурентность и ООП
Основы горутинКаналы и взаимодействиеБуферизованные и небуферизованные каналыОператор selectsync.Mutex и sync.RWMutexsync.WaitGroupПроектирование потокобезопасных структурПовторение — Worker Pool