1.5.3 接口组合与多态

1.5.3 接口组合与多态 #

Go 语言通过接口组合和多态性提供了强大的抽象能力。本节将深入探讨如何通过接口组合创建更复杂的抽象,以及如何利用多态性编写灵活可扩展的代码。

接口组合 #

接口组合是 Go 语言中一个重要的特性,它允许我们将多个小接口组合成更大的接口,遵循"组合优于继承"的设计原则。

基本接口组合 #

package main

import "fmt"

// 基础接口
type Reader interface {
    Read([]byte) (int, error)
}

type Writer interface {
    Write([]byte) (int, error)
}

type Closer interface {
    Close() error
}

// 组合接口
type ReadWriter interface {
    Reader
    Writer
}

type ReadWriteCloser interface {
    Reader
    Writer
    Closer
}

// 实现所有接口的类型
type File struct {
    name    string
    content []byte
    pos     int
    closed  bool
}

func NewFile(name string, content string) *File {
    return &File{
        name:    name,
        content: []byte(content),
        pos:     0,
        closed:  false,
    }
}

func (f *File) Read(data []byte) (int, error) {
    if f.closed {
        return 0, fmt.Errorf("文件已关闭")
    }

    if f.pos >= len(f.content) {
        return 0, fmt.Errorf("已到文件末尾")
    }

    n := copy(data, f.content[f.pos:])
    f.pos += n
    return n, nil
}

func (f *File) Write(data []byte) (int, error) {
    if f.closed {
        return 0, fmt.Errorf("文件已关闭")
    }

    f.content = append(f.content, data...)
    return len(data), nil
}

func (f *File) Close() error {
    if f.closed {
        return fmt.Errorf("文件已经关闭")
    }
    f.closed = true
    fmt.Printf("文件 %s 已关闭\n", f.name)
    return nil
}

func (f *File) String() string {
    return fmt.Sprintf("文件: %s, 内容: %s", f.name, string(f.content))
}

// 使用组合接口的函数
func ProcessReadWriter(rw ReadWriter, data []byte) {
    // 写入数据
    n, err := rw.Write(data)
    if err != nil {
        fmt.Printf("写入错误: %v\n", err)
        return
    }
    fmt.Printf("写入了 %d 字节\n", n)

    // 读取数据
    buffer := make([]byte, len(data))
    n, err = rw.Read(buffer)
    if err != nil {
        fmt.Printf("读取错误: %v\n", err)
        return
    }
    fmt.Printf("读取了 %d 字节: %s\n", n, string(buffer[:n]))
}

func ProcessReadWriteCloser(rwc ReadWriteCloser, data []byte) {
    defer rwc.Close() // 确保关闭资源

    ProcessReadWriter(rwc, data)
}

func main() {
    file := NewFile("test.txt", "初始内容\n")

    fmt.Println("=== 使用 ReadWriter 接口 ===")
    ProcessReadWriter(file, []byte("新增内容"))

    fmt.Println("\n=== 使用 ReadWriteCloser 接口 ===")
    file2 := NewFile("test2.txt", "")
    ProcessReadWriteCloser(file2, []byte("Hello, World!"))

    fmt.Println("\n=== 文件状态 ===")
    fmt.Println(file)
    fmt.Println(file2)
}

嵌入接口的高级用法 #

package main

import (
    "fmt"
    "time"
)

// 基础行为接口
type Movable interface {
    Move(x, y float64)
    GetPosition() (float64, float64)
}

type Drawable interface {
    Draw()
}

type Updatable interface {
    Update(deltaTime time.Duration)
}

// 组合接口
type GameObject interface {
    Movable
    Drawable
    Updatable
    GetName() string
}

// 可碰撞接口
type Collidable interface {
    GetBounds() (x, y, width, height float64)
    OnCollision(other Collidable)
}

// 游戏实体接口
type GameEntity interface {
    GameObject
    Collidable
    IsActive() bool
    SetActive(active bool)
}

// 玩家实现
type Player struct {
    name     string
    x, y     float64
    width    float64
    height   float64
    active   bool
    health   int
}

func NewPlayer(name string, x, y float64) *Player {
    return &Player{
        name:   name,
        x:      x,
        y:      y,
        width:  32,
        height: 32,
        active: true,
        health: 100,
    }
}

func (p *Player) Move(x, y float64) {
    p.x += x
    p.y += y
}

func (p *Player) GetPosition() (float64, float64) {
    return p.x, p.y
}

func (p *Player) Draw() {
    fmt.Printf("绘制玩家 %s 在位置 (%.1f, %.1f)\n", p.name, p.x, p.y)
}

func (p *Player) Update(deltaTime time.Duration) {
    // 玩家更新逻辑
    if p.health <= 0 {
        p.active = false
    }
}

func (p *Player) GetName() string {
    return p.name
}

func (p *Player) GetBounds() (x, y, width, height float64) {
    return p.x, p.y, p.width, p.height
}

func (p *Player) OnCollision(other Collidable) {
    fmt.Printf("玩家 %s 与 %T 发生碰撞\n", p.name, other)
    p.health -= 10
}

func (p *Player) IsActive() bool {
    return p.active
}

func (p *Player) SetActive(active bool) {
    p.active = active
}

// 敌人实现
type Enemy struct {
    name     string
    x, y     float64
    width    float64
    height   float64
    active   bool
    speed    float64
}

func NewEnemy(name string, x, y, speed float64) *Enemy {
    return &Enemy{
        name:   name,
        x:      x,
        y:      y,
        width:  24,
        height: 24,
        active: true,
        speed:  speed,
    }
}

func (e *Enemy) Move(x, y float64) {
    e.x += x * e.speed
    e.y += y * e.speed
}

func (e *Enemy) GetPosition() (float64, float64) {
    return e.x, e.y
}

func (e *Enemy) Draw() {
    fmt.Printf("绘制敌人 %s 在位置 (%.1f, %.1f)\n", e.name, e.x, e.y)
}

func (e *Enemy) Update(deltaTime time.Duration) {
    // 简单的AI:向左移动
    e.Move(-1, 0)
}

func (e *Enemy) GetName() string {
    return e.name
}

func (e *Enemy) GetBounds() (x, y, width, height float64) {
    return e.x, e.y, e.width, e.height
}

func (e *Enemy) OnCollision(other Collidable) {
    fmt.Printf("敌人 %s 与 %T 发生碰撞\n", e.name, other)
}

func (e *Enemy) IsActive() bool {
    return e.active
}

func (e *Enemy) SetActive(active bool) {
    e.active = active
}

// 游戏引擎
type GameEngine struct {
    entities []GameEntity
}

func NewGameEngine() *GameEngine {
    return &GameEngine{
        entities: make([]GameEntity, 0),
    }
}

func (ge *GameEngine) AddEntity(entity GameEntity) {
    ge.entities = append(ge.entities, entity)
}

func (ge *GameEngine) Update(deltaTime time.Duration) {
    fmt.Println("=== 更新游戏实体 ===")
    for _, entity := range ge.entities {
        if entity.IsActive() {
            entity.Update(deltaTime)
        }
    }
}

func (ge *GameEngine) Render() {
    fmt.Println("=== 渲染游戏实体 ===")
    for _, entity := range ge.entities {
        if entity.IsActive() {
            entity.Draw()
        }
    }
}

func (ge *GameEngine) CheckCollisions() {
    fmt.Println("=== 检查碰撞 ===")
    for i, entity1 := range ge.entities {
        if !entity1.IsActive() {
            continue
        }

        for j, entity2 := range ge.entities {
            if i >= j || !entity2.IsActive() {
                continue
            }

            if ge.isColliding(entity1, entity2) {
                entity1.OnCollision(entity2)
                entity2.OnCollision(entity1)
            }
        }
    }
}

func (ge *GameEngine) isColliding(e1, e2 Collidable) bool {
    x1, y1, w1, h1 := e1.GetBounds()
    x2, y2, w2, h2 := e2.GetBounds()

    return x1 < x2+w2 && x1+w1 > x2 && y1 < y2+h2 && y1+h1 > y2
}

func main() {
    engine := NewGameEngine()

    // 创建游戏实体
    player := NewPlayer("英雄", 100, 100)
    enemy1 := NewEnemy("哥布林", 200, 100, 0.5)
    enemy2 := NewEnemy("兽人", 150, 120, 0.3)

    // 添加到游戏引擎
    engine.AddEntity(player)
    engine.AddEntity(enemy1)
    engine.AddEntity(enemy2)

    // 模拟游戏循环
    for frame := 0; frame < 3; frame++ {
        fmt.Printf("\n========== 帧 %d ==========\n", frame+1)

        // 玩家移动
        if frame == 1 {
            player.Move(50, 0)
        }

        engine.Update(time.Millisecond * 16) // 60 FPS
        engine.CheckCollisions()
        engine.Render()
    }
}

多态性的实现 #

多态性允许我们使用统一的接口处理不同类型的对象,这是面向对象编程的核心概念之一。

多态性示例:图形处理系统 #

package main

import (
    "fmt"
    "math"
)

// 基础图形接口
type Shape interface {
    Area() float64
    Perimeter() float64
    String() string
}

// 可变形接口
type Scalable interface {
    Scale(factor float64)
}

// 可移动接口
type Movable interface {
    Move(dx, dy float64)
    GetPosition() (float64, float64)
}

// 完整的图形接口
type AdvancedShape interface {
    Shape
    Scalable
    Movable
}

// 矩形实现
type Rectangle struct {
    x, y          float64
    width, height float64
}

func NewRectangle(x, y, width, height float64) *Rectangle {
    return &Rectangle{x: x, y: y, width: width, height: height}
}

func (r *Rectangle) Area() float64 {
    return r.width * r.height
}

func (r *Rectangle) Perimeter() float64 {
    return 2 * (r.width + r.height)
}

func (r *Rectangle) String() string {
    return fmt.Sprintf("矩形[位置:(%.1f,%.1f), 尺寸:%.1fx%.1f]",
        r.x, r.y, r.width, r.height)
}

func (r *Rectangle) Scale(factor float64) {
    r.width *= factor
    r.height *= factor
}

func (r *Rectangle) Move(dx, dy float64) {
    r.x += dx
    r.y += dy
}

func (r *Rectangle) GetPosition() (float64, float64) {
    return r.x, r.y
}

// 圆形实现
type Circle struct {
    x, y   float64
    radius float64
}

func NewCircle(x, y, radius float64) *Circle {
    return &Circle{x: x, y: y, radius: radius}
}

func (c *Circle) Area() float64 {
    return math.Pi * c.radius * c.radius
}

func (c *Circle) Perimeter() float64 {
    return 2 * math.Pi * c.radius
}

func (c *Circle) String() string {
    return fmt.Sprintf("圆形[位置:(%.1f,%.1f), 半径:%.1f]",
        c.x, c.y, c.radius)
}

func (c *Circle) Scale(factor float64) {
    c.radius *= factor
}

func (c *Circle) Move(dx, dy float64) {
    c.x += dx
    c.y += dy
}

func (c *Circle) GetPosition() (float64, float64) {
    return c.x, c.y
}

// 三角形实现
type Triangle struct {
    x, y       float64
    base, height float64
}

func NewTriangle(x, y, base, height float64) *Triangle {
    return &Triangle{x: x, y: y, base: base, height: height}
}

func (t *Triangle) Area() float64 {
    return 0.5 * t.base * t.height
}

func (t *Triangle) Perimeter() float64 {
    // 假设是等腰三角形
    side := math.Sqrt((t.base/2)*(t.base/2) + t.height*t.height)
    return t.base + 2*side
}

func (t *Triangle) String() string {
    return fmt.Sprintf("三角形[位置:(%.1f,%.1f), 底边:%.1f, 高:%.1f]",
        t.x, t.y, t.base, t.height)
}

func (t *Triangle) Scale(factor float64) {
    t.base *= factor
    t.height *= factor
}

func (t *Triangle) Move(dx, dy float64) {
    t.x += dx
    t.y += dy
}

func (t *Triangle) GetPosition() (float64, float64) {
    return t.x, t.y
}

// 图形处理器
type ShapeProcessor struct {
    shapes []AdvancedShape
}

func NewShapeProcessor() *ShapeProcessor {
    return &ShapeProcessor{
        shapes: make([]AdvancedShape, 0),
    }
}

func (sp *ShapeProcessor) AddShape(shape AdvancedShape) {
    sp.shapes = append(sp.shapes, shape)
}

func (sp *ShapeProcessor) ProcessShapes() {
    fmt.Println("=== 处理所有图形 ===")

    totalArea := 0.0
    totalPerimeter := 0.0

    for i, shape := range sp.shapes {
        fmt.Printf("%d. %s\n", i+1, shape.String())
        fmt.Printf("   面积: %.2f, 周长: %.2f\n", shape.Area(), shape.Perimeter())

        totalArea += shape.Area()
        totalPerimeter += shape.Perimeter()
    }

    fmt.Printf("\n总面积: %.2f\n", totalArea)
    fmt.Printf("总周长: %.2f\n", totalPerimeter)
}

func (sp *ShapeProcessor) ScaleAllShapes(factor float64) {
    fmt.Printf("\n=== 缩放所有图形 (因子: %.1f) ===\n", factor)
    for _, shape := range sp.shapes {
        shape.Scale(factor)
    }
}

func (sp *ShapeProcessor) MoveAllShapes(dx, dy float64) {
    fmt.Printf("\n=== 移动所有图形 (偏移: %.1f, %.1f) ===\n", dx, dy)
    for _, shape := range sp.shapes {
        shape.Move(dx, dy)
    }
}

// 演示多态性的函数
func DemonstratePolymorphism(shapes []Shape) {
    fmt.Println("\n=== 多态性演示 ===")

    for _, shape := range shapes {
        // 同样的接口调用,不同的实现
        fmt.Printf("%s - 面积: %.2f\n", shape.String(), shape.Area())

        // 类型断言检查特定功能
        if scalable, ok := shape.(Scalable); ok {
            fmt.Printf("  -> 这个图形可以缩放\n")
            _ = scalable // 避免未使用变量警告
        }

        if movable, ok := shape.(Movable); ok {
            x, y := movable.GetPosition()
            fmt.Printf("  -> 这个图形可以移动,当前位置: (%.1f, %.1f)\n", x, y)
        }
    }
}

func main() {
    processor := NewShapeProcessor()

    // 创建不同类型的图形
    rect := NewRectangle(0, 0, 10, 5)
    circle := NewCircle(20, 20, 3)
    triangle := NewTriangle(50, 50, 8, 6)

    // 添加到处理器
    processor.AddShape(rect)
    processor.AddShape(circle)
    processor.AddShape(triangle)

    // 处理图形
    processor.ProcessShapes()

    // 缩放所有图形
    processor.ScaleAllShapes(1.5)
    processor.ProcessShapes()

    // 移动所有图形
    processor.MoveAllShapes(10, 10)
    processor.ProcessShapes()

    // 演示多态性
    shapes := []Shape{rect, circle, triangle}
    DemonstratePolymorphism(shapes)
}

接口的动态特性 #

Go 语言的接口具有动态特性,可以在运行时检查和转换类型:

package main

import (
    "fmt"
    "reflect"
)

// 定义多个接口
type Speaker interface {
    Speak() string
}

type Walker interface {
    Walk() string
}

type Flyer interface {
    Fly() string
}

// 多功能接口
type Animal interface {
    Speaker
    GetName() string
}

// 实现类型
type Dog struct {
    Name string
}

func (d Dog) Speak() string {
    return "汪汪"
}

func (d Dog) Walk() string {
    return "狗在走路"
}

func (d Dog) GetName() string {
    return d.Name
}

type Bird struct {
    Name string
}

func (b Bird) Speak() string {
    return "啾啾"
}

func (b Bird) Fly() string {
    return "鸟在飞翔"
}

func (b Bird) GetName() string {
    return b.Name
}

type Fish struct {
    Name string
}

func (f Fish) Speak() string {
    return "咕噜咕噜"
}

func (f Fish) GetName() string {
    return f.Name
}

// 动态能力检测器
type CapabilityDetector struct{}

func (cd CapabilityDetector) DetectCapabilities(animal Animal) {
    fmt.Printf("\n=== 检测 %s 的能力 ===\n", animal.GetName())

    // 基本能力
    fmt.Printf("说话: %s\n", animal.Speak())

    // 检查行走能力
    if walker, canWalk := animal.(Walker); canWalk {
        fmt.Printf("行走: %s\n", walker.Walk())
    } else {
        fmt.Println("行走: 不会走路")
    }

    // 检查飞行能力
    if flyer, canFly := animal.(Flyer); canFly {
        fmt.Printf("飞行: %s\n", flyer.Fly())
    } else {
        fmt.Println("飞行: 不会飞")
    }

    // 使用反射获取更多信息
    animalType := reflect.TypeOf(animal)
    fmt.Printf("类型: %s\n", animalType)
    fmt.Printf("方法数量: %d\n", animalType.NumMethod())

    for i := 0; i < animalType.NumMethod(); i++ {
        method := animalType.Method(i)
        fmt.Printf("  方法 %d: %s\n", i+1, method.Name)
    }
}

// 多态处理函数
func ProcessAnimals(animals []Animal) {
    fmt.Println("=== 处理动物列表 ===")

    walkers := make([]Walker, 0)
    flyers := make([]Flyer, 0)

    for _, animal := range animals {
        fmt.Printf("%s 说: %s\n", animal.GetName(), animal.Speak())

        // 分类收集不同能力的动物
        if walker, ok := animal.(Walker); ok {
            walkers = append(walkers, walker)
        }

        if flyer, ok := animal.(Flyer); ok {
            flyers = append(flyers, flyer)
        }
    }

    // 处理会走路的动物
    if len(walkers) > 0 {
        fmt.Println("\n会走路的动物:")
        for _, walker := range walkers {
            fmt.Printf("  %s\n", walker.Walk())
        }
    }

    // 处理会飞的动物
    if len(flyers) > 0 {
        fmt.Println("\n会飞的动物:")
        for _, flyer := range flyers {
            fmt.Printf("  %s\n", flyer.Fly())
        }
    }
}

// 接口转换示例
func InterfaceConversion() {
    fmt.Println("\n=== 接口转换示例 ===")

    var speaker Speaker

    // 不同类型赋值给同一接口
    animals := []Animal{
        Dog{Name: "旺财"},
        Bird{Name: "小鸟"},
        Fish{Name: "金鱼"},
    }

    for _, animal := range animals {
        speaker = animal // Animal 接口包含 Speaker 接口
        fmt.Printf("%s: %s\n", animal.GetName(), speaker.Speak())

        // 尝试转换回原始类型
        switch v := speaker.(type) {
        case Dog:
            fmt.Printf("  这是一只狗: %s\n", v.Walk())
        case Bird:
            fmt.Printf("  这是一只鸟: %s\n", v.Fly())
        case Fish:
            fmt.Printf("  这是一条鱼,只会游泳\n")
        default:
            fmt.Printf("  未知动物类型: %T\n", v)
        }
    }
}

func main() {
    // 创建不同类型的动物
    dog := Dog{Name: "旺财"}
    bird := Bird{Name: "小鸟"}
    fish := Fish{Name: "金鱼"}

    animals := []Animal{dog, bird, fish}

    // 处理动物
    ProcessAnimals(animals)

    // 检测能力
    detector := CapabilityDetector{}
    for _, animal := range animals {
        detector.DetectCapabilities(animal)
    }

    // 接口转换示例
    InterfaceConversion()
}

接口的最佳实践 #

1. 设计小而专注的接口 #

// 好的设计
type Reader interface {
    Read([]byte) (int, error)
}

type Writer interface {
    Write([]byte) (int, error)
}

// 通过组合创建复杂接口
type ReadWriter interface {
    Reader
    Writer
}

2. 使用接口进行依赖注入 #

package main

import "fmt"

// 服务接口
type Logger interface {
    Log(message string)
}

type Database interface {
    Save(data string) error
    Load(id string) (string, error)
}

// 具体实现
type ConsoleLogger struct{}

func (cl ConsoleLogger) Log(message string) {
    fmt.Printf("[LOG] %s\n", message)
}

type MemoryDatabase struct {
    data map[string]string
}

func NewMemoryDatabase() *MemoryDatabase {
    return &MemoryDatabase{
        data: make(map[string]string),
    }
}

func (md *MemoryDatabase) Save(data string) error {
    md.data["key"] = data
    return nil
}

func (md *MemoryDatabase) Load(id string) (string, error) {
    if data, exists := md.data[id]; exists {
        return data, nil
    }
    return "", fmt.Errorf("数据不存在")
}

// 业务服务
type UserService struct {
    logger Logger
    db     Database
}

func NewUserService(logger Logger, db Database) *UserService {
    return &UserService{
        logger: logger,
        db:     db,
    }
}

func (us *UserService) CreateUser(name string) error {
    us.logger.Log(fmt.Sprintf("创建用户: %s", name))
    return us.db.Save(name)
}

func main() {
    logger := ConsoleLogger{}
    db := NewMemoryDatabase()

    service := NewUserService(logger, db)
    service.CreateUser("张三")
}

小结 #

本节深入探讨了 Go 语言中接口组合和多态性的概念,包括:

  • 接口组合的基本原理和高级用法
  • 多态性的实现和应用
  • 接口的动态特性和类型检查
  • 接口设计的最佳实践

通过接口组合和多态性,我们可以构建出灵活、可扩展且易于维护的代码架构。这些概念是 Go 语言面向对象编程的核心,也是编写高质量 Go 代码的重要基础。

在实际开发中,合理使用接口组合和多态性可以帮助我们:

  • 降低代码耦合度
  • 提高代码的可测试性
  • 增强代码的可扩展性
  • 实现更清晰的架构设计

掌握这些概念将为后续学习更高级的 Go 语言特性打下坚实的基础。