Golang中的动作组合实践与应用

Golang中的动作组合实践与应用 大家好,我是Go语言的新手。我想尝试一下由动作组合而成的类。例如,一个玩家可以walk()fly(),但也许一个怪物只能walk()

在这种情况下,walk()fly()方法都需要访问玩家的位置,所以我想出了以下代码。然而,我想知道这是否真正符合Go语言的惯用法。我不太喜欢的一点是,同一个指针被多个对象所拥有。

// You can edit this code!
// Click here and start typing.
package main

import "fmt"

type PositionComponent struct {
	x int
	y int
}

type Positionable interface {
	GetPositionComponent() *PositionComponent
	SetPositionComponent(x int, y int)
}

func (p *PositionComponent) GetPositionComponent() *PositionComponent {
	return p
}

func (p *PositionComponent) SetPositionComponent(x int, y int) {
	p.x = x
	p.y = y
}

type Walker struct {
	Positionable
}

type Flyer struct {
	Positionable
}

func (w *Walker) walk() {
	w.GetPositionComponent().x += 1
	fmt.Printf("Walked: %s\n", w.GetPositionComponent())
}

func (w *Flyer) fly() {
	w.GetPositionComponent().y += 1
	fmt.Printf("Flew: %s\n", w.GetPositionComponent())
}

type Player struct {
	*PositionComponent
	Walker
	Flyer
}

func main() {
	pComp := PositionComponent{2, 2}
	p := Player{&pComp, Walker{&pComp}, Flyer{&pComp}}
	p.walk()
	p.fly()
	fmt.Println(p.PositionComponent)
}

Go playground


更多关于Golang中的动作组合实践与应用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang中的动作组合实践与应用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


在Go中实现动作组合时,更惯用的做法是使用结构体嵌入和接口组合。你的代码方向正确,但可以简化。以下是改进版本:

package main

import "fmt"

type Position struct {
    X int
    Y int
}

func (p *Position) Move(x, y int) {
    p.X += x
    p.Y += y
}

func (p Position) String() string {
    return fmt.Sprintf("(%d, %d)", p.X, p.Y)
}

type Walker struct {
    *Position
}

func (w *Walker) Walk() {
    w.Move(1, 0)
    fmt.Printf("Walked to %s\n", w.Position)
}

type Flyer struct {
    *Position
}

func (f *Flyer) Fly() {
    f.Move(0, 1)
    fmt.Printf("Flew to %s\n", f.Position)
}

type Player struct {
    *Position
    Walker
    Flyer
}

type Monster struct {
    *Position
    Walker
}

func main() {
    // Player可以走和飞
    playerPos := &Position{2, 2}
    player := Player{
        Position: playerPos,
        Walker:   Walker{playerPos},
        Flyer:    Flyer{playerPos},
    }
    
    player.Walk()
    player.Fly()
    fmt.Printf("Player final position: %s\n", player.Position)
    
    // Monster只能走
    monsterPos := &Position{5, 5}
    monster := Monster{
        Position: monsterPos,
        Walker:   Walker{monsterPos},
    }
    
    monster.Walk()
    // monster.Fly() // 编译错误:Monster没有Fly方法
    fmt.Printf("Monster final position: %s\n", monster.Position)
    
    // 验证位置共享
    fmt.Printf("Player X: %d, Monster X: %d\n", player.X, monster.X)
}

另一种更简洁的实现方式,使用接口:

package main

import "fmt"

type Mover interface {
    Move(x, y int)
    Position() (int, int)
}

type Position struct {
    x, y int
}

func (p *Position) Move(x, y int) {
    p.x += x
    p.y += y
}

func (p *Position) Position() (int, int) {
    return p.x, p.y
}

type WalkBehavior struct {
    Mover
}

func (w *WalkBehavior) Walk() {
    w.Move(1, 0)
    x, y := w.Position()
    fmt.Printf("Walked to (%d, %d)\n", x, y)
}

type FlyBehavior struct {
    Mover
}

func (f *FlyBehavior) Fly() {
    f.Move(0, 1)
    x, y := f.Position()
    fmt.Printf("Flew to (%d, %d)\n", x, y)
}

type Player struct {
    *Position
    *WalkBehavior
    *FlyBehavior
}

func NewPlayer(x, y int) *Player {
    pos := &Position{x, y}
    return &Player{
        Position:     pos,
        WalkBehavior: &WalkBehavior{pos},
        FlyBehavior:  &FlyBehavior{pos},
    }
}

type Monster struct {
    *Position
    *WalkBehavior
}

func NewMonster(x, y int) *Monster {
    pos := &Position{x, y}
    return &Monster{
        Position:     pos,
        WalkBehavior: &WalkBehavior{pos},
    }
}

func main() {
    player := NewPlayer(2, 2)
    player.Walk()
    player.Fly()
    
    monster := NewMonster(5, 5)
    monster.Walk()
}

第一个示例展示了直接的结构体嵌入,第二个示例使用接口提供了更好的抽象。两种方式都避免了显式的Get/Set方法,更符合Go的惯用法。多个对象共享同一个指针在Go中是常见的,只要注意生命周期管理即可。

回到顶部