Ôn tập: hồ sơ học sinh
Thuộc phần Lập trình hướng đối tượng trong hành trình GO của Coddy. Bài học 51 trên 107.
Thử thách
DễHãy xây dựng một hệ thống hồ sơ sinh viên minh họa cách đóng gói đúng cách. Bạn sẽ tạo một cấu trúc quản lý sinh viên, trong đó dữ liệu học tập nhạy cảm được bảo vệ nhưng vẫn cho phép truy cập có kiểm soát thông qua các phương thức được thiết kế hợp lý.
Bạn sẽ sắp xếp code trong hai tệp:
student.go: Tạo một cấu trúcStudentbảo vệ thông tin nhạy cảm nhưng vẫn hiển thị dữ liệu công khai an toàn.Namecủa sinh viên nên được xuất (có thể truy cập công khai), còngrade(float64) vàstudentID(string) nên không được xuất để bảo vệ thông tin nhạy cảm này.Triển khai những nội dung sau:
- Một hàm khởi tạo
NewStudent(name, id string, initialGrade float64) *Studenttạo sinh viên. Chỉ đặt điểm ban đầu nếu điểm nằm trong khoảng từ 0 đến 100 (bao gồm cả hai giá trị); nếu không, mặc định là 0. - Một hàm truy xuất
Grade() float64trả về điểm hiện tại - Một hàm truy xuất
StudentID() stringtrả về mã sinh viên - Một hàm thiết lập
SetGrade(newGrade float64) boolchỉ cập nhật điểm nếu giá trị mới nằm trong khoảng từ 0 đến 100 (bao gồm cả hai giá trị). Trả vềtruenếu điểm được cập nhật, còn lại trả vềfalse. - Một phương thức
Summary() stringtrả về định dạng:[Name] (ID: [studentID]) - Grade: [grade]
- Một hàm khởi tạo
main.go: Đọc thông tin sinh viên từ đầu vào, tạo sinh viên bằng hàm khởi tạo, sau đó thực hiện các thao tác với điểm. Hiển thị bản tóm tắt của sinh viên sau khi tạo và sau mỗi lần thử cập nhật điểm.
Đầu vào sẽ gồm những thông tin sau:
- Dòng 1: Tên sinh viên
- Dòng 2: Mã sinh viên
- Dòng 3: Điểm ban đầu
- Dòng 4: Điểm mới thứ nhất cần đặt
- Dòng 5: Điểm mới thứ hai cần đặt
Sau khi tạo sinh viên, hãy in bản tóm tắt của họ. Sau đó, thử cập nhật từng điểm. Nếu cập nhật thành công, hãy in bản tóm tắt đã cập nhật; nếu bị từ chối, hãy in Invalid grade rejected. Định dạng tất cả giá trị điểm với hai chữ số thập phân.
Ví dụ, với Emma Wilson, STU001, 85.5, 92.0 và 150, đầu ra của bạn sẽ là:
Emma Wilson (ID: STU001) - Grade: 85.50
Emma Wilson (ID: STU001) - Grade: 92.00
Invalid grade rejectedLần cập nhật cuối thất bại vì 150 nằm ngoài phạm vi hợp lệ. Phương thức thiết lập của bạn thực thi quy tắc này, giúp giữ cho dữ liệu của sinh viên luôn hợp lệ. Hãy chú ý rằng studentID và grade không bao giờ có thể được truy cập trực tiếp: code bên ngoài phải dùng các phương thức truy xuất và thiết lập của bạn để tương tác với dữ liệu được bảo vệ này.
Tự làm thử
package main
import (
"bufio"
"fmt"
"os"
"strconv"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
// Đọc tên học sinh
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)
// Đọc mã số học sinh
id, _ := reader.ReadString('\n')
id = strings.TrimSpace(id)
// Đọc điểm ban đầu
initialGradeStr, _ := reader.ReadString('\n')
initialGrade, _ := strconv.ParseFloat(strings.TrimSpace(initialGradeStr), 64)
// Đọc điểm mới thứ nhất
newGrade1Str, _ := reader.ReadString('\n')
newGrade1, _ := strconv.ParseFloat(strings.TrimSpace(newGrade1Str), 64)
// Đọc điểm mới thứ hai
newGrade2Str, _ := reader.ReadString('\n')
newGrade2, _ := strconv.ParseFloat(strings.TrimSpace(newGrade2Str), 64)
// TODO: Tạo học sinh mới bằng hàm khởi tạo (constructor) NewStudent
// TODO: In ra bản tóm tắt thông tin học sinh sau khi tạo
// TODO: Thử cập nhật điểm lần thứ nhất
// Nếu thành công, in ra bản tóm tắt đã cập nhật
// Nếu bị từ chối, in ra "Invalid grade rejected"
// TODO: Thử cập nhật điểm lần thứ hai
// Nếu thành công, in ra bản tóm tắt đã cập nhật
// Nếu bị từ chối, in ra "Invalid grade rejected"
// Gợi ý: Dùng fmt.Sprintf với %.2f để định dạng điểm trong Summary()
_ = newGrade1 // Xóa dòng này khi bạn dùng biến
_ = newGrade2 // Xóa dòng này khi bạn dùng biến
}
Tất cả bài học trong Lập trình hướng đối tượng
1Nền tảng OOP trong Go
Tệp bên ngoàiWorkspace và module trong GoPackage và importTên được export và không được exportGiới thiệu về OOP trong GoStruct như lớpĐịnh nghĩa phương thức cho structReceiver kiểu con trỏ và kiểu giá trịKhởi tạo structHàm khởi tạoÔn tập: máy tính đơn giản4Interface
Giới thiệu về interfaceTriển khai ngầm địnhInterface như một hợp đồngInterface rỗng (any)Khẳng định kiểuswitch kiểuKết hợp interfaceInterface Stringer và ErrorÔn tập: Máy tính hình học7Tính đóng gói
Trường được xuất và không được xuấtĐóng gói ở cấp packagePhương thức getter và setterẨn thông tin trong GoÔn tập: hồ sơ học sinh10Generics (Go 1.18 trở lên)
Giới thiệu về GenericsTham số kiểuRàng buộc kiểuStruct tổng quátGiải pháp thay thế cho phương thức tổng quátÔn tập: tập hợp tổng quát13Các mẫu thiết kế phần 1
Giới thiệu về mẫu thiết kếMẫu SingletonMẫu FactoryMẫu Abstract FactoryMẫu ObserverMẫu Strategy2Tìm hiểu chuyên sâu về kiểu dữ liệu và struct
Kiểu cơ bản và kiểu tổng hợpĐịnh nghĩa kiểu dữ liệu tùy chỉnhThẻ structStruct ẩn danhStruct lồng nhauGiá trị zero và giá trị mặc địnhÔn tập: sổ liên lạc5Ưu tiên kết hợp hơn kế thừa
Vì sao Go không có kế thừaNhập môn nhúng structTự động nâng phương thứcNhúng nhiều structNhúng và kết tậpChe khuất phương thức được nhúngÔn tập: hệ phân cấp nhân viên8Xử lý lỗi và lập trình hướng đối tượng
Giao diện errorCác kiểu lỗi tùy chỉnhBọc lỗi với fmt.ErrorfLỗi sentinelerrors.Is() và errors.As()Panic, defer và recoverÔn tập: trình phân tích tệp3Con trỏ và bộ nhớ
Cơ bản về con trỏ trong GoCon trỏ đến structTruyền theo giá trị và tham chiếuHàm new()Thu gom rác trong GoÔn tập: xây dựng danh sách liên kết6Đa hình trong Go
Đa hình qua interfaceĐịnh kiểu vịt trong GoQuy tắc thỏa mãn interfaceCác tập hợp đa hìnhTiêm phụ thuộcÔn tập: bộ xử lý thanh toán9Lập trình đồng thời và lập trình hướng đối tượng
Cơ bản về goroutineChannel và giao tiếpChannel có bộ đệm và không có bộ đệmCâu lệnh selectsync.Mutex và sync.RWMutexsync.WaitGroupThiết kế struct an toàn luồngÔn tập: worker poolTự luyện tập: Trình biên dịch Go online