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 语言特性打下坚实的基础。