Menu
Coddy logo textTech

eラーニングプラットフォーム

CoddyのGOジャーニー「オブジェクト指向プログラミング」セクションの一部 — レッスン 105/107。

challenge icon

チャレンジ

簡単

コースや学生を管理し、学習の進捗を追跡するEラーニングプラットフォームを構築しましょう!構造体、インターフェース、コンポジション、ポリモーフィズムを組み合わせて、学生がコースに登録し、レッスンを完了できるまとまりのあるシステムを作成します。

コードは5つのファイルに整理します:

  • lesson.go: 個々の学習単位を表す Lesson 構造体を定義します。各レッスンには IDTitle、および Duration(分単位)があります。Lesson へのポインタを返す NewLesson コンストラクタを含めます。
  • course.go: IDTitleInstructor、および *Lesson ポインタのスライスを含む Course 構造体を作成します。NewCourse コンストラクタと AddLesson メソッドを含めます。また、コース内のすべてのレッスンの所要時間の合計を返す TotalDuration() int メソッドも実装します。
  • student.go: IDName、および Email フィールドを持つ Student 構造体を定義します。NewStudent コンストラクタを含めます。
  • enrollment.go: ここで進捗追跡の魔法が起こります。学生とコースをリンクし、完了したレッスンを追跡する Enrollment 構造体を作成します。以下を持つ必要があります:
    • Student へのポインタ
    • Course へのポインタ
    • CompletedLessons マップ(レッスンIDからブール値へのマッピング)

    パーセンテージ(0.0 から 100.0)を返す Progress() float64 メソッドを持つ Progressable インターフェースを定義します。

    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、名前、メールアドレスを読み取ります。学生とコースをリンクする登録(enrollment)を作成します。

    次に、操作の数を読み取ります。各操作は complete [lessonID] または progress のいずれかです。complete 操作の場合は、結果メッセージを出力します。progress 操作の場合は、小数点以下1桁にフォーマットされた進捗状況にパーセント記号を続けて出力します。

以下の入力が提供されます:

  • コースID、タイトル、インストラクター(3行)
  • レッスンの数、次に各レッスンのID、タイトル、所要時間(各3行)
  • 学生ID、名前、メールアドレス(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)

	// 1行を読み込むためのヘルパー関数
	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("") // 実際の結果に置き換える
		}
	}
}

オブジェクト指向プログラミングのすべてのレッスン