Kết hợp 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 31 trên 107.
Go cho phép bạn xây dựng các giao diện lớn hơn bằng cách kết hợp những giao diện nhỏ hơn. Thay vì định nghĩa một giao diện lớn với nhiều phương thức, bạn nhúng các giao diện hiện có vào định nghĩa giao diện mới.
type Reader interface {
Read() string
}
type Writer interface {
Write(data string)
}
// ReadWriter kết hợp cả hai giao diện (interface)
type ReadWriter interface {
Reader
Writer
}Interface ReadWriter hiện yêu cầu cả hai phương thức Read() và Write(). Bất kỳ kiểu nào triển khai cả hai phương thức đều thỏa mãn ReadWriter, đồng thời cũng thỏa mãn riêng Reader và Writer.
type File struct {
Name string
}
func (f File) Read() string { return "file content" }
func (f File) Write(data string) { fmt.Println("Writing:", data) }
func Process(rw ReadWriter) {
content := rw.Read()
rw.Write(content)
}
func main() {
f := File{Name: "data.txt"}
Process(f) // File đáp ứng giao diện ReadWriter
}Cách tiếp cận kết hợp này giúp giao diện gọn và tập trung. Bạn có thể kết hợp chúng tùy theo nhu cầu để tạo các hợp đồng chính xác cho hàm của mình. Thư viện chuẩn của Go sử dụng rộng rãi mẫu này, chẳng hạn như io.ReadWriter, kết hợp io.Reader và io.Writer.
Thử thách
DễHãy xây dựng một hệ thống phát đa phương tiện để minh họa cách kết hợp các interface. Bạn sẽ tạo những interface nhỏ, tập trung vào một mục đích, sau đó kết hợp chúng thành một interface tổng hợp mạnh hơn mà một kiểu duy nhất có thể đáp ứng.
Bạn sẽ sắp xếp code trong hai tệp:
media.go: Định nghĩa ba interface và một struct triển khai tất cả:- Một interface
Playercó phương thứcPlay() string - Một interface
Recordercó phương thứcRecord(content string) string - Một interface
MediaDevicekết hợp cảPlayervàRecorder - Một struct
SmartDevicecó trườngNamevà triển khai tất cả các phương thức cần thiết
- Một interface
main.go: Tạo các hàm để minh họa cách sử dụng cùng mộtSmartDevicethông qua các kiểu interface khác nhau. Viết ba hàm:UsePlayernhận mộtPlayervà gọi phương thứcPlaycủa nóUseRecordernhận mộtRecordervà một chuỗi nội dung, sau đó gọiRecordUseMediaDevicenhận mộtMediaDevicevà một chuỗi nội dung, sau đó gọi cảRecordlẫnPlay
SmartDevice, rồi minh họa cách sử dụng thiết bị đó thông qua cả ba kiểu interface.
Đầu vào sẽ gồm:
- Dòng 1: Tên thiết bị
- Dòng 2: Nội dung cần ghi
Các phương thức của bạn cần trả về chuỗi theo định dạng sau:
Play():[Name] is playingRecord(content):[Name] recorded: [content]
Ví dụ, với MyPhone và voice memo, đầu ra sẽ là:
MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playingHai dòng đầu cho biết thiết bị được sử dụng thông qua từng interface riêng lẻ (Player và Recorder). Hai dòng cuối cho biết thiết bị được sử dụng thông qua interface tổng hợp MediaDevice, vốn yêu cầu cả hai khả năng. Hãy lưu ý rằng một SmartDevice duy nhất đáp ứng cả ba interface vì nó có đủ hai phương thức cần thiết.
Tự làm thử
package main
import (
"bufio"
"fmt"
"os"
)
// TODO: Triển khai UsePlayer nhận một Player và gọi phương thức (method) Play của nó
// Hàm này cần in ra kết quả của Play()
// TODO: Triển khai UseRecorder nhận một Recorder và một chuỗi (string) content
// Hàm này cần in ra kết quả của Record(content)
// TODO: Triển khai UseMediaDevice nhận một MediaDevice và một chuỗi content
// Hàm này cần in ra kết quả của Record(content), rồi đến Play()
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
deviceName := scanner.Text()
scanner.Scan()
content := scanner.Text()
// TODO: Tạo một SmartDevice với tên đã cho
// TODO: Sử dụng thiết bị thông qua giao diện (interface) Player
// TODO: Sử dụng thiết bị thông qua giao diện Recorder
// TODO: Sử dụng thiết bị thông qua giao diện MediaDevice
_ = deviceName
_ = content
fmt.Println("Implement the solution")
}
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