Phương thức getter và setter
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 49 trên 107.
Vì bạn không thể truy cập trực tiếp các trường không được xuất từ bên ngoài một package, bạn cần cung cấp các phương thức (method) để kiểm soát quyền truy cập. Những phương thức này thường được gọi là phương thức lấy giá trị (getter) và phương thức thiết lập giá trị (setter).
Trong Go, quy tắc đặt tên hàm lấy giá trị rất đơn giản: dùng tên trường với chữ cái đầu viết hoa. Đừng thêm tiền tố "Get", chỉ cần dùng Balance(), không dùng GetBalance():
type BankAccount struct {
balance int // Không được xuất ra ngoài package
}
// Getter: trả về giá trị
func (b *BankAccount) Balance() int {
return b.balance
}
// Setter: thay đổi giá trị sau khi kiểm tra tính hợp lệ
func (b *BankAccount) SetBalance(amount int) {
if amount >= 0 {
b.balance = amount
}
}
Sức mạnh thực sự của các phương thức setter nằm ở việc thêm bước xác thực hoặc logic nghiệp vụ. Thay vì để code bên ngoài tự do gán bất kỳ giá trị nào, bạn kiểm soát những giá trị được phép:
func (b *BankAccount) Deposit(amount int) bool {
if amount <= 0 {
return false
}
b.balance += amount
return true
}
Phương thức Deposit này hoạt động như một phương thức thiết lập chuyên biệt, giúp thực thi quy tắc: không cho phép gửi tiền âm. Code bên ngoài phải gọi các phương thức của bạn, nhờ đó struct luôn ở trạng thái hợp lệ. Đây là tính đóng gói trong thực tế: ẩn dữ liệu nhưng cung cấp các hành vi được kiểm soát.
Thử thách
DễHãy xây dựng một trình chuyển đổi nhiệt độ để minh họa cách đóng gói phù hợp bằng các phương thức getter và setter. Bạn sẽ tạo một struct lưu nhiệt độ nội bộ theo độ C, đồng thời cung cấp quyền truy cập có kiểm soát thông qua các phương thức có bước kiểm tra hợp lệ.
Bạn sẽ sắp xếp code trong hai tệp:
temperature.go: Tạo structTemperaturecó trườngcelsiuskhông được export (float64). Triển khai các phương thức sau:Celsius()- getter trả về nhiệt độ hiện tại theo độ CSetCelsius(value float64)- setter chỉ chấp nhận các giá trị bằng hoặc cao hơn độ không tuyệt đối (-273.15). Nếu giá trị thấp hơn ngưỡng này, nhiệt độ phải giữ nguyên.Fahrenheit()- trả về nhiệt độ đã chuyển sang độ Fahrenheit theo công thức:(celsius * 9/5) + 32SetFahrenheit(value float64)- chuyển đầu vào từ độ Fahrenheit sang độ C rồi lưu lại, nhưng chỉ khi giá trị độ C sau khi chuyển đổi bằng hoặc cao hơn -273.15
NewTemperature(celsius float64) *Temperatuređể tạo nhiệt độ được khởi tạo bằng giá trị đã cho (giả sử đầu vào của hàm khởi tạo hợp lệ).main.go: Đọc các giá trị nhiệt độ từ đầu vào và minh họa các phương thức getter/setter. Tạo một nhiệt độ, hiển thị giá trị theo cả hai đơn vị, sau đó thử đặt các giá trị mới và hiển thị kết quả.
Đầu vào sẽ gồm các giá trị sau:
- Dòng 1: Giá trị độ C ban đầu
- Dòng 2: Giá trị độ C mới cần đặt
- Dòng 3: Giá trị độ Fahrenheit mới cần đặt
Định dạng tất cả đầu ra nhiệt độ với hai chữ số thập phân. In ra lần lượt như sau:
- Sau khi tạo:
C: [celsius] F: [fahrenheit] - Sau khi đặt độ C:
C: [celsius] F: [fahrenheit] - Sau khi đặt độ Fahrenheit:
C: [celsius] F: [fahrenheit]
Ví dụ, với các giá trị 25, -300 và 212, đầu ra sẽ là:
C: 25.00 F: 77.00
C: 25.00 F: 77.00
C: 100.00 F: 212.00Lưu ý rằng dòng thứ hai hiển thị các giá trị không đổi vì -300 thấp hơn độ không tuyệt đối, nên setter đã từ chối giá trị đó. Dòng thứ ba hiển thị nhiệt độ sau khi đặt thành công 212°F (chuyển đổi thành 100°C). Đó là sức mạnh của setter. Chúng thực thi các quy tắc giúp dữ liệu của bạn luôn hợp lệ.
Tự làm thử
package main
import (
"fmt"
)
func main() {
// Đọc các giá trị đầu vào
var initialCelsius float64
var newCelsius float64
var newFahrenheit float64
fmt.Scanln(&initialCelsius)
fmt.Scanln(&newCelsius)
fmt.Scanln(&newFahrenheit)
// TODO: Tạo một Temperature mới bằng hàm khởi tạo
// TODO: In các giá trị ban đầu theo định dạng "C: [celsius] F: [fahrenheit]" với 2 chữ số thập phân
// TODO: Thử đặt giá trị Celsius mới và in kết quả
// TODO: Thử đặt giá trị Fahrenheit mới và in kết quả
}
Bài học này có một bài trắc nghiệm ngắn. Bắt đầu bài học để trả lời và theo dõi tiế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