Платформа онлайн-обучения
Часть раздела Объектно-ориентированное программирование путешествия по GO на Coddy. Урок 105 из 107.
Задание
ЛегкоДавайте создадим платформу электронного обучения, которая управляет курсами, студентами и отслеживает прогресс обучения! Вы объедините структуры, интерфейсы, композицию и полиморфизм, чтобы создать целостную систему, в которой студенты могут записываться на курсы и завершать lesson.
Вы организуете код в пяти файлах:
lesson.go: Определите структуруLesson, представляющую отдельные учебные единицы. Каждый lesson имеетID,TitleиDuration(в минутах). Добавьте конструкторNewLesson, который возвращает указатель на Lesson.course.go: Создайте структуруCourse, содержащуюID,Title,Instructorи срез указателей*Lesson. Добавьте конструкторNewCourseи методAddLesson. Также реализуйте методTotalDuration() int, который возвращает сумму продолжительностей всех lessons в course.student.go: Определите структуруStudentс полямиID,NameиEmail. Добавьте конструкторNewStudent.enrollment.go: Здесь происходит вся магия отслеживания прогресса. Создайте структуруEnrollment, которая связывает студента с course и отслеживает, какие lessons они завершили. Она должна содержать:- Указатель на
Student - Указатель на
Course - Карту
CompletedLessons(идентификатор lesson и логическое значение)
Определите интерфейс
Progressableс методомProgress() float64, который возвращает процент (0.0–100.0).Реализуйте следующие методы для Enrollment:
NewEnrollment(student *Student, course *Course) *Enrollment: конструктор, инициализирующий пустую карту завершённых lessonsCompleteLesson(lessonID string) string: отмечает lesson как завершённый. Возвращаетlesson not found, если lesson не существует в course,already completed, если он уже завершён, илиcompletedв случае успехаProgress() float64: возвращает процент завершённых lessons (завершённые/общее количество * 100) или 0.0, если в course нет lessons
- Указатель на
main.go: Создайте платформу и обрабатывайте операции enrollment.Считайте ID, название и instructor course. Затем считайте количество lessons, а также ID, название и продолжительность каждого lesson. Считайте ID, имя и email студента. Создайте enrollment, связывающий студента с course.
Затем считайте количество операций. Каждая операция — это либо
complete [lessonID], либоprogress. Для операций complete выведите сообщение с результатом. Для операций progress выведите прогресс, отформатированный с точностью до одного знака после запятой, а затем знак процента.
Будут предоставлены следующие входные данные:
- ID, название и Instructor course (3 строки)
- Количество lessons, затем ID, название и Duration каждого lesson (по 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 использует композицию для связывания студентов и courses, а интерфейс Progressable позволяет любому типу сообщать свой статус завершения. Благодаря этой конструкции систему легко расширять. Вы можете добавить отслеживание прогресса отдельных lessons или целых learning paths, используя тот же интерфейс!
Попробуйте сами
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("") // Заменить на фактический результат
}
}
}
Все уроки раздела Объектно-ориентированное программирование
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Потренируйтесь самостоятельно: Онлайн-компилятор Go