Go 继承
Go 语言没有传统面向对象语言中的继承机制,而是通过组合(composition)和接口(interface)来实现代码重用和多态。本章将详细介绍 Go 语言的"继承"实现方式。
📋 组合优于继承
结构体嵌入
go
package main
import "fmt"
// 基础结构体
type Animal struct {
Name string
Age int
}
// Animal 的方法
func (a Animal) Eat() {
fmt.Printf("%s 正在吃东西\n", a.Name)
}
func (a Animal) Sleep() {
fmt.Printf("%s 正在睡觉\n", a.Name)
}
func (a Animal) GetInfo() string {
return fmt.Sprintf("名字: %s, 年龄: %d", a.Name, a.Age)
}
// 通过嵌入实现"继承"
type Dog struct {
Animal // 嵌入 Animal 结构体
Breed string
}
// Dog 特有的方法
func (d Dog) Bark() {
fmt.Printf("%s 正在汪汪叫\n", d.Name)
}
func (d Dog) GetInfo() string {
return fmt.Sprintf("狗 - 名字: %s, 年龄: %d, 品种: %s", d.Name, d.Age, d.Breed)
}
// Cat 结构体
type Cat struct {
Animal
Color string
}
func (c Cat) Meow() {
fmt.Printf("%s 正在喵喵叫\n", c.Name)
}
func (c Cat) GetInfo() string {
return fmt.Sprintf("猫 - 名字: %s, 年龄: %d, 颜色: %s", c.Name, c.Age, c.Color)
}
func structEmbedding() {
fmt.Println("=== 结构体嵌入演示 ===")
// 创建 Dog 实例
dog := Dog{
Animal: Animal{Name: "旺财", Age: 3},
Breed: "金毛",
}
// 创建 Cat 实例
cat := Cat{
Animal: Animal{Name: "咪咪", Age: 2},
Color: "白色",
}
// 使用嵌入的方法
dog.Eat() // 调用 Animal 的方法
dog.Sleep() // 调用 Animal 的方法
dog.Bark() // 调用 Dog 自己的方法
cat.Eat() // 调用 Animal 的方法
cat.Sleep() // 调用 Animal 的方法
cat.Meow() // 调用 Cat 自己的方法
// 方法重写(方法覆盖)
fmt.Println("\n信息显示:")
fmt.Println(dog.GetInfo()) // 调用 Dog 重写的方法
fmt.Println(cat.GetInfo()) // 调用 Cat 重写的方法
// 直接访问嵌入结构体的方法
fmt.Println("\n直接调用 Animal 方法:")
fmt.Println(dog.Animal.GetInfo()) // 调用原始 Animal 方法
fmt.Println(cat.Animal.GetInfo()) // 调用原始 Animal 方法
}
func main() {
structEmbedding()
}多层嵌入
go
package main
import "fmt"
// 基础实体
type Entity struct {
ID int
Name string
}
func (e Entity) GetID() int {
return e.ID
}
func (e Entity) GetName() string {
return e.Name
}
// 生物
type LivingBeing struct {
Entity
IsAlive bool
}
func (lb LivingBeing) CheckAlive() string {
if lb.IsAlive {
return fmt.Sprintf("%s 是活着的", lb.Name)
}
return fmt.Sprintf("%s 已经死亡", lb.Name)
}
// 动物
type Creature struct {
LivingBeing
Species string
}
func (c Creature) GetSpecies() string {
return c.Species
}
func (c Creature) Move() {
fmt.Printf("%s (%s) 正在移动\n", c.Name, c.Species)
}
// 哺乳动物
type Mammal struct {
Creature
HasFur bool
}
func (m Mammal) GiveBirth() {
fmt.Printf("%s 正在生产幼崽\n", m.Name)
}
func (m Mammal) GetDescription() string {
furStatus := "无毛"
if m.HasFur {
furStatus = "有毛"
}
return fmt.Sprintf("ID: %d, 名字: %s, 物种: %s, %s, 状态: %s",
m.ID, m.Name, m.Species, furStatus,
map[bool]string{true: "活着", false: "死亡"}[m.IsAlive])
}
func multiLevelEmbedding() {
fmt.Println("=== 多层嵌入演示 ===")
// 创建哺乳动物实例
lion := Mammal{
Creature: Creature{
LivingBeing: LivingBeing{
Entity: Entity{ID: 1, Name: "狮子王"},
IsAlive: true,
},
Species: "狮子",
},
HasFur: true,
}
elephant := Mammal{
Creature: Creature{
LivingBeing: LivingBeing{
Entity: Entity{ID: 2, Name: "大象"},
IsAlive: true,
},
Species: "非洲象",
},
HasFur: false,
}
// 使用各层的方法
fmt.Printf("ID: %d\n", lion.GetID()) // Entity 方法
fmt.Printf("名字: %s\n", lion.GetName()) // Entity 方法
fmt.Println(lion.CheckAlive()) // LivingBeing 方法
fmt.Printf("物种: %s\n", lion.GetSpecies()) // Creature 方法
lion.Move() // Creature 方法
lion.GiveBirth() // Mammal 方法
fmt.Println("\n详细信息:")
fmt.Println(lion.GetDescription())
fmt.Println(elephant.GetDescription())
}
func main() {
multiLevelEmbedding()
}🎯 接口实现多态
接口与组合
go
package main
import "fmt"
// 定义接口
type Speaker interface {
Speak() string
}
type Mover interface {
Move() string
}
type Worker interface {
Work() string
}
// 组合接口
type Employee interface {
Speaker
Mover
Worker
}
// 基础人类结构
type Person struct {
Name string
Age int
}
func (p Person) Speak() string {
return fmt.Sprintf("%s 说:你好!", p.Name)
}
func (p Person) Move() string {
return fmt.Sprintf("%s 正在走路", p.Name)
}
func (p Person) GetInfo() string {
return fmt.Sprintf("姓名: %s, 年龄: %d", p.Name, p.Age)
}
// 程序员
type Programmer struct {
Person
Language string
}
func (pr Programmer) Work() string {
return fmt.Sprintf("%s 正在用 %s 编程", pr.Name, pr.Language)
}
func (pr Programmer) Debug() string {
return fmt.Sprintf("%s 正在调试代码", pr.Name)
}
// 教师
type Teacher struct {
Person
Subject string
}
func (t Teacher) Work() string {
return fmt.Sprintf("%s 正在教授 %s", t.Name, t.Subject)
}
func (t Teacher) Teach() string {
return fmt.Sprintf("%s 正在备课", t.Name)
}
// 司机
type Driver struct {
Person
LicenseType string
}
func (d Driver) Work() string {
return fmt.Sprintf("%s 正在开车 (%s 驾照)", d.Name, d.LicenseType)
}
func (d Driver) Drive() string {
return fmt.Sprintf("%s 正在安全驾驶", d.Name)
}
// 演示多态
func demonstratePolymorphism(employees []Employee) {
fmt.Println("=== 多态演示 ===")
for i, emp := range employees {
fmt.Printf("\n员工 %d:\n", i+1)
fmt.Printf(" 说话: %s\n", emp.Speak())
fmt.Printf(" 移动: %s\n", emp.Move())
fmt.Printf(" 工作: %s\n", emp.Work())
// 类型断言获取具体类型的特有方法
switch e := emp.(type) {
case Programmer:
fmt.Printf(" 特殊技能: %s\n", e.Debug())
case Teacher:
fmt.Printf(" 特殊技能: %s\n", e.Teach())
case Driver:
fmt.Printf(" 特殊技能: %s\n", e.Drive())
}
}
}
func interfaceComposition() {
fmt.Println("=== 接口与组合演示 ===")
// 创建不同类型的员工
programmer := Programmer{
Person: Person{Name: "张三", Age: 28},
Language: "Go",
}
teacher := Teacher{
Person: Person{Name: "李四", Age: 35},
Subject: "数学",
}
driver := Driver{
Person: Person{Name: "王五", Age: 42},
LicenseType: "A2",
}
// 所有类型都实现了 Employee 接口
employees := []Employee{programmer, teacher, driver}
demonstratePolymorphism(employees)
// 单独使用不同接口
fmt.Println("\n=== 单独接口使用 ===")
var speakers []Speaker = []Speaker{programmer, teacher, driver}
var workers []Worker = []Worker{programmer, teacher, driver}
fmt.Println("所有人说话:")
for _, speaker := range speakers {
fmt.Printf(" %s\n", speaker.Speak())
}
fmt.Println("\n所有人工作:")
for _, worker := range workers {
fmt.Printf(" %s\n", worker.Work())
}
}
func main() {
interfaceComposition()
}🏗️ 组合模式实践
组件化设计
go
package main
import "fmt"
// 可见性组件
type Visible struct {
X, Y int
Width int
Height int
Visible bool
}
func (v *Visible) Show() {
v.Visible = true
fmt.Printf("显示组件在位置 (%d, %d)\n", v.X, v.Y)
}
func (v *Visible) Hide() {
v.Visible = false
fmt.Printf("隐藏组件\n")
}
func (v *Visible) Move(x, y int) {
v.X, v.Y = x, y
fmt.Printf("移动组件到 (%d, %d)\n", x, y)
}
// 可点击组件
type Clickable struct {
Enabled bool
}
func (c *Clickable) Click() {
if c.Enabled {
fmt.Println("组件被点击")
} else {
fmt.Println("组件已禁用,无法点击")
}
}
func (c *Clickable) Enable() {
c.Enabled = true
fmt.Println("启用组件")
}
func (c *Clickable) Disable() {
c.Enabled = false
fmt.Println("禁用组件")
}
// 可输入文本组件
type TextInput struct {
Text string
MaxLength int
}
func (ti *TextInput) SetText(text string) {
if len(text) <= ti.MaxLength {
ti.Text = text
fmt.Printf("设置文本: \"%s\"\n", text)
} else {
fmt.Printf("文本太长,最大长度: %d\n", ti.MaxLength)
}
}
func (ti *TextInput) GetText() string {
return ti.Text
}
func (ti *TextInput) Clear() {
ti.Text = ""
fmt.Println("清空文本")
}
// 按钮组件(组合多个特性)
type Button struct {
Visible
Clickable
Label string
}
func NewButton(label string, x, y int) *Button {
return &Button{
Visible: Visible{
X: x, Y: y,
Width: 100, Height: 30,
Visible: true,
},
Clickable: Clickable{Enabled: true},
Label: label,
}
}
func (b *Button) Render() {
if b.Visible.Visible {
fmt.Printf("渲染按钮 \"%s\" 在 (%d, %d)\n", b.Label, b.X, b.Y)
}
}
// 输入框组件
type InputField struct {
Visible
Clickable
TextInput
Placeholder string
}
func NewInputField(placeholder string, x, y int, maxLength int) *InputField {
return &InputField{
Visible: Visible{
X: x, Y: y,
Width: 200, Height: 25,
Visible: true,
},
Clickable: Clickable{Enabled: true},
TextInput: TextInput{MaxLength: maxLength},
Placeholder: placeholder,
}
}
func (inf *InputField) Render() {
if inf.Visible.Visible {
displayText := inf.Text
if displayText == "" {
displayText = inf.Placeholder
}
fmt.Printf("渲染输入框 \"%s\" 在 (%d, %d)\n", displayText, inf.X, inf.Y)
}
}
// 面板组件
type Panel struct {
Visible
Children []UIComponent
}
type UIComponent interface {
Render()
Show()
Hide()
}
func NewPanel(x, y, width, height int) *Panel {
return &Panel{
Visible: Visible{
X: x, Y: y,
Width: width, Height: height,
Visible: true,
},
Children: make([]UIComponent, 0),
}
}
func (p *Panel) AddChild(child UIComponent) {
p.Children = append(p.Children, child)
}
func (p *Panel) Render() {
if p.Visible.Visible {
fmt.Printf("渲染面板在 (%d, %d) 大小 %dx%d\n",
p.X, p.Y, p.Width, p.Height)
for _, child := range p.Children {
child.Render()
}
}
}
func componentComposition() {
fmt.Println("=== 组件化设计演示 ===")
// 创建按钮
submitBtn := NewButton("提交", 100, 100)
cancelBtn := NewButton("取消", 220, 100)
// 创建输入框
nameInput := NewInputField("请输入姓名", 100, 50, 50)
emailInput := NewInputField("请输入邮箱", 100, 75, 100)
// 创建面板
formPanel := NewPanel(50, 25, 300, 150)
// 添加组件到面板
formPanel.AddChild(nameInput)
formPanel.AddChild(emailInput)
formPanel.AddChild(submitBtn)
formPanel.AddChild(cancelBtn)
// 渲染整个界面
fmt.Println("初始渲染:")
formPanel.Render()
// 交互演示
fmt.Println("\n=== 用户交互 ===")
// 输入文本
nameInput.SetText("张三")
emailInput.SetText("zhangsan@example.com")
// 点击按钮
submitBtn.Click()
// 移动组件
submitBtn.Move(150, 120)
// 禁用和隐藏
cancelBtn.Disable()
cancelBtn.Click() // 尝试点击被禁用的按钮
emailInput.Hide()
fmt.Println("\n更新后渲染:")
formPanel.Render()
}
func main() {
componentComposition()
}🎯 实际应用示例
游戏实体系统
go
package main
import (
"fmt"
"math"
)
// 位置组件
type Position struct {
X, Y float64
}
func (p *Position) MoveTo(x, y float64) {
p.X, p.Y = x, y
}
func (p *Position) MoveBy(dx, dy float64) {
p.X += dx
p.Y += dy
}
func (p Position) DistanceTo(other Position) float64 {
dx := p.X - other.X
dy := p.Y - other.Y
return math.Sqrt(dx*dx + dy*dy)
}
// 生命值组件
type Health struct {
Current int
Maximum int
}
func (h *Health) TakeDamage(damage int) {
h.Current -= damage
if h.Current < 0 {
h.Current = 0
}
fmt.Printf("受到 %d 点伤害,当前生命值: %d/%d\n", damage, h.Current, h.Maximum)
}
func (h *Health) Heal(amount int) {
h.Current += amount
if h.Current > h.Maximum {
h.Current = h.Maximum
}
fmt.Printf("恢复 %d 点生命值,当前生命值: %d/%d\n", amount, h.Current, h.Maximum)
}
func (h Health) IsAlive() bool {
return h.Current > 0
}
// 攻击组件
type Combat struct {
AttackPower int
AttackRange float64
}
func (c Combat) CanAttack(attacker, target Position) bool {
distance := attacker.DistanceTo(target)
return distance <= c.AttackRange
}
func (c Combat) Attack(target *Health) {
fmt.Printf("发动攻击,造成 %d 点伤害\n", c.AttackPower)
target.TakeDamage(c.AttackPower)
}
// 移动组件
type Movement struct {
Speed float64
MoveRange float64
}
func (m Movement) CanMoveTo(current, target Position) bool {
distance := current.DistanceTo(target)
return distance <= m.MoveRange
}
// 游戏实体接口
type GameEntity interface {
GetPosition() Position
GetName() string
Update()
}
// 角色实体
type Character struct {
Name string
Position
Health
Combat
Movement
}
func (c Character) GetPosition() Position {
return c.Position
}
func (c Character) GetName() string {
return c.Name
}
func (c *Character) Update() {
fmt.Printf("%s 位置: (%.1f, %.1f), 生命值: %d/%d\n",
c.Name, c.X, c.Y, c.Current, c.Maximum)
}
// 建筑实体
type Building struct {
Name string
Position
Health
}
func (b Building) GetPosition() Position {
return b.Position
}
func (b Building) GetName() string {
return b.Name
}
func (b *Building) Update() {
fmt.Printf("%s 位置: (%.1f, %.1f), 耐久度: %d/%d\n",
b.Name, b.X, b.Y, b.Current, b.Maximum)
}
// 可移动实体(只有角色可以移动)
type Movable interface {
Move(x, y float64) bool
}
func (c *Character) Move(x, y float64) bool {
target := Position{X: x, Y: y}
if c.Movement.CanMoveTo(c.Position, target) {
c.Position.MoveTo(x, y)
fmt.Printf("%s 移动到 (%.1f, %.1f)\n", c.Name, x, y)
return true
}
fmt.Printf("%s 无法移动到 (%.1f, %.1f),超出移动范围\n", c.Name, x, y)
return false
}
// 可攻击实体
type Attacker interface {
AttackEntity(target GameEntity) bool
}
func (c *Character) AttackEntity(target GameEntity) bool {
targetPos := target.GetPosition()
if !c.Combat.CanAttack(c.Position, targetPos) {
fmt.Printf("%s 无法攻击 %s,超出攻击范围\n", c.Name, target.GetName())
return false
}
fmt.Printf("%s 攻击 %s\n", c.Name, target.GetName())
// 根据目标类型进行攻击
switch t := target.(type) {
case *Character:
c.Combat.Attack(&t.Health)
case *Building:
c.Combat.Attack(&t.Health)
}
return true
}
func gameEntitySystem() {
fmt.Println("=== 游戏实体系统演示 ===")
// 创建角色
warrior := &Character{
Name: "战士",
Position: Position{X: 0, Y: 0},
Health: Health{Current: 100, Maximum: 100},
Combat: Combat{AttackPower: 25, AttackRange: 2.0},
Movement: Movement{Speed: 1.0, MoveRange: 3.0},
}
mage := &Character{
Name: "法师",
Position: Position{X: 5, Y: 5},
Health: Health{Current: 80, Maximum: 80},
Combat: Combat{AttackPower: 35, AttackRange: 4.0},
Movement: Movement{Speed: 0.8, MoveRange: 2.5},
}
// 创建建筑
tower := &Building{
Name: "箭塔",
Position: Position{X: 10, Y: 10},
Health: Health{Current: 200, Maximum: 200},
}
// 游戏实体列表
entities := []GameEntity{warrior, mage, tower}
fmt.Println("初始状态:")
for _, entity := range entities {
entity.Update()
}
// 游戏逻辑演示
fmt.Println("\n=== 游戏回合 1 ===")
// 战士移动
if movable, ok := warrior.(Movable); ok {
movable.Move(3, 3)
}
// 法师尝试攻击战士
if attacker, ok := mage.(Attacker); ok {
attacker.AttackEntity(warrior)
}
fmt.Println("\n回合 1 结束状态:")
for _, entity := range entities {
entity.Update()
}
fmt.Println("\n=== 游戏回合 2 ===")
// 战士继续靠近法师
warrior.Move(4, 4)
// 战士攻击法师
warrior.AttackEntity(mage)
// 法师反击
mage.AttackEntity(warrior)
fmt.Println("\n回合 2 结束状态:")
for _, entity := range entities {
entity.Update()
}
// 检查存活状态
fmt.Println("\n=== 存活检查 ===")
for _, entity := range entities {
if char, ok := entity.(*Character); ok {
if char.Health.IsAlive() {
fmt.Printf("%s 仍然存活\n", char.Name)
} else {
fmt.Printf("%s 已死亡\n", char.Name)
}
}
}
}
func main() {
gameEntitySystem()
}🎓 小结
本章我们学习了 Go 语言的"继承"实现方式:
- ✅ 结构体嵌入:通过嵌入实现代码重用和方法继承
- ✅ 多层嵌入:复杂的继承层次结构
- ✅ 接口组合:通过接口实现多态和行为继承
- ✅ 组合模式:组件化设计和灵活的代码组织
- ✅ 实际应用:游戏实体系统的完整实现
Go 语言的"组合优于继承"设计理念提供了更灵活、更清晰的代码组织方式,避免了传统继承的复杂性。
接下来,我们将学习 Go 语言标准库,了解 Go 丰富的内置功能。
组合设计建议
- 优先使用组合而不是复杂的嵌入层次
- 通过接口定义行为,通过结构体实现功能
- 保持组件的单一职责和高内聚
- 合理使用方法重写来定制行为