Giới thiệu về interface
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 25 trên 107.
Interface trong Go định nghĩa một tập hợp các chữ ký phương thức mà không triển khai chúng. Nó mô tả kiểu dữ liệu có thể làm gì, chứ không phải cách kiểu đó thực hiện. Bất kỳ kiểu dữ liệu nào triển khai tất cả phương thức trong một interface đều tự động đáp ứng interface đó.
Đây là cách bạn định nghĩa một giao diện:
type Speaker interface {
Speak() string
}Giao diện Speaker này yêu cầu mọi kiểu triển khai giao diện phải có phương thức Speak() trả về một chuỗi. Giờ đây, bạn có thể dùng bất kỳ struct nào có phương thức này ở nơi cần một Speaker.
type Dog struct {
Name string
}
func (d Dog) Speak() string {
return d.Name + " says woof!"
}
type Cat struct {
Name string
}
func (c Cat) Speak() string {
return c.Name + " says meow!"
}Cả Dog và Cat đều đáp ứng giao diện Speaker vì chúng đều có phương thức Speak() với chữ ký chính xác. Giờ đây, bạn có thể viết các hàm chấp nhận mọi Speaker:
func MakeSound(s Speaker) {
fmt.Println(s.Speak())
}
func main() {
dog := Dog{Name: "Buddy"}
cat := Cat{Name: "Whiskers"}
MakeSound(dog) // Buddy kêu gâu gâu!
MakeSound(cat) // Whiskers kêu meo meo!
}Giao diện cho phép bạn viết code linh hoạt, có thể tái sử dụng và hoạt động với mọi kiểu đáp ứng các yêu cầu của giao diện, bất kể cách triển khai bên dưới.
Thử thách
DễHãy xây dựng một hệ thống mô tả phương tiện để minh họa cách giao diện cho phép các kiểu dữ liệu khác nhau có chung hành vi. Bạn sẽ tạo một giao diện mà nhiều kiểu phương tiện có thể đáp ứng, sau đó dùng giao diện này để mô tả mọi phương tiện theo cùng một cách.
Bạn sẽ sắp xếp code trong hai tệp:
vehicles.go: Định nghĩa giao diệnDescribervới một phương thức duy nhất làDescribe() string. Sau đó, tạo hai cấu trúc đáp ứng giao diện này:Carcó các trườngBrandvàModel(cả hai đều là chuỗi)Bicyclecó các trườngType(chuỗi) vàGears(số nguyên)
Describe()trả về chuỗi mô tả phương tiện.main.go: Tạo hàm có tênPrintDescription, nhận vào bất kỳ giá trị nào đáp ứng giao diệnDescribervà in ra kết quả gọi phương thứcDescribe()của giá trị đó. Đọc thông tin phương tiện từ đầu vào, tạo cả một chiếc xe hơi và một chiếc xe đạp, rồi dùng hàm của bạn để in ra phần mô tả cho từng phương tiện.
Đầu vào sẽ gồm:
- Dòng 1: Hãng xe hơi
- Dòng 2: Mẫu xe hơi
- Dòng 3: Loại xe đạp
- Dòng 4: Số bánh răng (số nguyên)
Các phương thức Describe() cần trả về chuỗi theo những định dạng sau:
- Xe hơi:
[Brand] [Model] - Xe đạp:
[Type] bike with [Gears] gears
Ví dụ, với đầu vào Toyota, Camry, Mountain và 21, đầu ra sẽ là:
Toyota Camry
Mountain bike with 21 gearsĐiểm mấu chốt là hàm PrintDescription hoạt động với mọi kiểu dữ liệu có phương thức Describe(). Hàm này không cần biết nó đang xử lý một chiếc xe hơi, xe đạp hay bất kỳ loại phương tiện nào khác mà bạn có thể bổ sung sau này.
Tự làm thử
package main
import (
"fmt"
)
// TODO: Tạo hàm (function) PrintDescription nhận bất kỳ Describer nào
// và in ra kết quả khi gọi phương thức (method) Describe() của nó
func main() {
// Đọc đầu vào
var carBrand string
var carModel string
var bicycleType string
var gears int
fmt.Scanln(&carBrand)
fmt.Scanln(&carModel)
fmt.Scanln(&bicycleType)
fmt.Scanln(&gears)
// TODO: Tạo Car với thương hiệu và mẫu xe từ đầu vào
// TODO: Tạo Bicycle với loại xe và số bánh răng từ đầu vào
// TODO: Dùng PrintDescription để in ra mô tả của ô tô
// TODO: Dùng PrintDescription để in ra mô tả của xe đạp
}
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