Skip to content

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 丰富的内置功能。

组合设计建议

  • 优先使用组合而不是复杂的嵌入层次
  • 通过接口定义行为,通过结构体实现功能
  • 保持组件的单一职责和高内聚
  • 合理使用方法重写来定制行为

本站内容仅供学习和研究使用。