遮蔽嵌入的方法
本课属于 Coddy GO 学习旅程的“面向对象编程”单元。第 39 课,共 107 课。
有时,你需要让外层结构体提供自己的方法实现,而嵌入类型已经有这个方法了。这称为遮蔽,它可以让你用自定义行为覆盖提升的方法。
当你在外层结构体上定义一个与嵌入方法同名的方法时,外层方法优先:
type Animal struct {
Name string
}
func (a Animal) Speak() string {
return "Some sound"
}
type Dog struct {
Animal
Breed string
}
func (d Dog) Speak() string {
return "Woof!"
}
现在,当你在 Dog 上调用 Speak() 时,会使用外层方法:
func main() {
d := Dog{Animal: Animal{Name: "Rex"}, Breed: "Labrador"}
fmt.Println(d.Speak()) // Woof!:Dog 的方法
fmt.Println(d.Animal.Speak()) // Some sound:Animal 的方法
}
嵌入的方法并没有消失。你仍然可以通过嵌入类型的名称显式访问它。如果你想自定义行为,同时保留原始实现以供使用,这种模式就很有用。比如,你可以在重写的方法中调用原始实现:
func (d Dog) Speak() string {
return d.Animal.Speak() + " (but actually Woof!)"
}
通过遮蔽,你可以控制对外提供哪种行为,同时通过显式限定仍可访问原始行为。
挑战
简单我们来构建一个通知系统,让不同的通知渠道可以自定义消息的格式和发送方式。你将使用方法遮蔽,让特定渠道覆盖默认行为,同时在需要时仍能访问原始实现。
你将把代码分别放在三个文件中:
base.go:创建一个BaseNotification结构体,其中包含Title和Priority字段(两者都是字符串)。为它添加一个Format() string方法,以标准格式返回通知:[Priority] Title。channels.go:创建两种嵌入BaseNotification并用各自实现遮蔽Format方法的通知渠道类型:EmailNotification,包含一个Recipient字段。它的Format()应返回Email to [Recipient]: [Priority] TitleSlackNotification,包含一个Channel字段。它的Format()应调用嵌入的BaseNotification.Format()方法,并在结果前添加#[Channel]:
main.go:从输入中读取通知详情,创建这两种通知,并通过打印以下内容展示方法遮蔽:EmailNotification格式化后的输出(使用它遮蔽后的方法)EmailNotification的基础格式(显式调用嵌入的方法)SlackNotification格式化后的输出(内部会使用基础方法)
输入内容如下:
- 第 1 行:通知标题
- 第 2 行:优先级
- 第 3 行:电子邮件收件人
- 第 4 行:Slack 频道名称
例如,输入 Server Alert、HIGH、admin@company.com 和 ops-alerts 时,输出应为:
Email to admin@company.com: HIGH Server Alert
[HIGH] Server Alert
#ops-alerts: [HIGH] Server Alert注意,EmailNotification 会完全替换基础格式,而 SlackNotification 则会调用原始方法并添加频道信息来增强格式。这两种方式都展示了如何有效使用方法遮蔽。
亲手试试
package main
import (
"bufio"
"fmt"
"os"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// 读取通知标题
scanner.Scan()
title := scanner.Text()
// 读取优先级
scanner.Scan()
priority := scanner.Text()
// 读取邮件收件人
scanner.Scan()
recipient := scanner.Text()
// 读取 Slack 频道名称
scanner.Scan()
channel := scanner.Text()
// TODO:使用基础通知、标题、优先级和收件人创建 EmailNotification
// TODO:使用基础通知、标题、优先级和频道创建 SlackNotification
// TODO:打印 EmailNotification 的格式化输出(使用其覆盖嵌入方法的方法)
// TODO:打印 EmailNotification 的基础格式(显式调用嵌入的方法)
// TODO:打印 SlackNotification 的格式化输出
fmt.Println() // 占位代码,实现时删除
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: Go 在线编译器