接口组合
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 31 课,共 107 课。
Go 允许你通过组合较小的接口来构建更大的接口。你不必定义一个包含许多方法的大接口,而是可以在新的接口定义中嵌入已有的接口。
type Reader interface {
Read() string
}
type Writer interface {
Write(data string)
}
// ReadWriter 组合了这两个接口
type ReadWriter interface {
Reader
Writer
}ReadWriter 接口现在要求同时实现 Read() 和 Write() 方法。任何实现了这两个方法的类型都满足 ReadWriter 接口,也分别满足 Reader 和 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 实现了 ReadWriter 接口
}这种组合方式能让接口保持小巧且专注。你可以根据需要灵活组合它们,为函数创建精确的约定。Go 的标准库广泛使用这种模式,例如 io.ReadWriter,它组合了 io.Reader 和 io.Writer。
挑战
简单让我们构建一个媒体播放器系统,来演示接口组合。你将创建一些小型、专注的接口,然后将它们组合成一个功能更强大的接口,让单个类型满足该接口的要求。
你将把代码分到两个文件中:
media.go:定义三个接口和一个实现所有接口的结构体:- 一个包含
Play() string方法的Player接口 - 一个包含
Record(content string) string方法的Recorder接口 - 一个组合了
Player和Recorder的MediaDevice接口 - 一个包含
Name字段,并实现所有必需方法的SmartDevice结构体
- 一个包含
main.go:创建函数,演示如何通过不同的接口类型使用同一个SmartDevice。编写三个函数:UsePlayer:接收一个Player,并调用它的Play方法UseRecorder:接收一个Recorder和一个内容字符串,然后调用RecordUseMediaDevice:接收一个MediaDevice和一个内容字符串,然后同时调用Record和Play
SmartDevice,并演示通过这三种接口类型使用它。
将提供以下输入:
- 第 1 行:设备名称
- 第 2 行:要录制的内容
你的方法应按以下格式返回字符串:
Play():[Name] is playingRecord(content):[Name] recorded: [content]
例如,给定 MyPhone 和 voice memo,你的输出应为:
MyPhone is playing
MyPhone recorded: voice memo
MyPhone recorded: voice memo
MyPhone is playing前两行展示了通过单独的接口(Player 和 Recorder)使用设备的情况。最后两行展示了通过组合接口 MediaDevice 使用设备的情况,该接口要求设备同时具备两种能力。注意,由于你的 SmartDevice 实现了两个必需的方法,因此它满足全部三个接口的要求。
亲手试试
package main
import (
"bufio"
"fmt"
"os"
)
// TODO:实现 UsePlayer,接收一个 Player 并调用其 Play 方法
// 它应打印 Play() 的结果
// TODO:实现 UseRecorder,接收一个 Recorder 和一个 content 字符串
// 它应打印 Record(content) 的结果
// TODO:实现 UseMediaDevice,接收一个 MediaDevice 和一个 content 字符串
// 它应先打印 Record(content) 的结果,再打印 Play() 的结果
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
deviceName := scanner.Text()
scanner.Scan()
content := scanner.Text()
// TODO:用给定的名称创建一个 SmartDevice
// TODO:通过 Player 接口使用该设备
// TODO:通过 Recorder 接口使用该设备
// TODO:通过 MediaDevice 接口使用该设备
_ = deviceName
_ = content
fmt.Println("Implement the solution")
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器