Menu
CoddyTech

接口组合

本课属于 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。

challenge icon

挑战

简单

让我们构建一个媒体播放器系统,来演示接口组合。你将创建一些小型、专注的接口,然后将它们组合成一个功能更强大的接口,让单个类型满足该接口的要求。

你将把代码分到两个文件中:

  • media.go:定义三个接口和一个实现所有接口的结构体:
    • 一个包含 Play() string 方法的 Player 接口
    • 一个包含 Record(content string) string 方法的 Recorder 接口
    • 一个组合了 Player 和 Recorder 的 MediaDevice 接口
    • 一个包含 Name 字段,并实现所有必需方法的 SmartDevice 结构体
  • main.go:创建函数,演示如何通过不同的接口类型使用同一个 SmartDevice。编写三个函数:
    • UsePlayer:接收一个 Player,并调用它的 Play 方法
    • UseRecorder:接收一个 Recorder 和一个内容字符串,然后调用 Record
    • UseMediaDevice:接收一个 MediaDevice 和一个内容字符串,然后同时调用 Record 和 Play
    从输入中读取设备名称和内容,创建一个 SmartDevice,并演示通过这三种接口类型使用它。

将提供以下输入:

  • 第 1 行:设备名称
  • 第 2 行:要录制的内容

你的方法应按以下格式返回字符串:

  • Play():[Name] is playing
  • Record(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")
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Go 在线编译器