Go 创建实现接口的结构实例的函数

Go 创建实现接口的结构实例的函数,go,Go,这个问题与之相关,并在此基础上进一步展开 我的设置如下所示: 我正在创建一个服务器端的游戏,客户端可以选择不同的游戏模式。这些模式是通过不同的结构实现的,它们各自实现了一些方法,所有这些方法都是它们自己在包引擎中的文件,例如: package engines import "fmt" type Square struct { tiles []int players []bool } func NewSquare() *Square { return &Squ

这个问题与之相关,并在此基础上进一步展开

我的设置如下所示:

我正在创建一个服务器端的游戏,客户端可以选择不同的游戏模式。这些模式是通过不同的结构实现的,它们各自实现了一些方法,所有这些方法都是它们自己在
包引擎中的文件,例如:

package engines

import "fmt"

type Square struct {
    tiles []int
    players []bool
}

func NewSquare() *Square {
    return &Square{
        [25]int{}[:],
        []bool{false, false},
    }
}

func (e *Square) AddPlayer() (int, error) {
    for id := range e.players {
        if !e.players[id] {
            e.players[id] = true
            return id, nil
        }
    }
    return -1, fmt.Printf("game already full")
}
在主程序包中,当创建一个新游戏时,我使用一个map调用相应游戏模式的
newSomething
函数。每个引擎都满足界面
gameEngine

package main

import "engines"

type gameEngine interface {
    AddPlayer() (int, error)
}

type GameMode int
const (
    SQUARE   GameMode = 0
    TRIANGLE GameMode = 1
)
此接口在主包中定义有两个主要原因:

  • 将接口定义放在使用该接口的同一文件中可以提高可读性。如果我不确定某个对象的功能,我可以滚动到接口定义并检查
  • 将接口定义放在
    包引擎中
    感觉就像回到类显式声明它们实现的接口的情况,go的其中一个功能是不需要的
  • 这意味着在我的引擎实现的文件中,如
    Square.go
    Triangle.go
    ,我没有访问接口的权限,相应的新函数必须返回各自的类型,这使得它们分别为
    func()*Square
    func()*Triangle
    (见上文)

    现在我无法在
    map[GameMode]func()游戏引擎中直接使用这些新函数,因为它们的类型错误。我目前的解决方案是使用一个相当详细的内联函数来转换它们(受链接问题中的一个答案启发):

    这张地图看起来很笨重,很做作,但据我所知,这是用这张地图的唯一方法

    有没有更好的方法或设计模式来实现我的目标?

    • func-JoinGame(mode-GameMode)(int,error)
      是我的客户端界面的一部分,它是整个过程的起点,必须保留其签名
    • 类型游戏引擎界面
      应保留在主软件包中
    • 在实施新模式(例如,
      Hexagon.go
      )时,只需在一个位置创建文件并注册
      newHexagon
      函数

    您宁愿定义一个新类型(func的别名),也不愿定义一个接口。
    键入AddPlayer func()(游戏模式,错误)

    并使用
    引擎
    包中的函数封装此映射,您可以使用
    init()
    在单独的文件中添加新的句柄函数(按需)。比如:
    发动机/主机。转到

    package引擎
    输入游戏模式int
    常数(
    平方=iota
    三角
    )
    键入AddPlayer func()(游戏模式,错误)
    var newGameFuncs=make(映射[GameMode]AddPlayer)
    func GetAddPlayerFuncByGameMode(gm GameMode)AddPlayer{
    返回newGameFuncs[gm]
    }
    
    引擎/方格前进

    package引擎
    func init(){
    newGameFuncs[SQUARE]=engineSquare{}.NewSquare
    }
    类型engineSquare结构{}
    func(engineSquare)NewSquare()(游戏模式,错误){
    返回平方,零
    }
    
    main.go
    您可以像这样使用它:

    主程序包
    导入e.“/engins”
    func main(){
    e、 GetAddPlayerFuncByGameMode(e.SQUARE)
    }
    
    如果闭包困扰您,您可以用switch语句替换映射,但您现在拥有的是一个合理的解决方案。没错,我甚至没有想到switch语句(我最初的解决方案不起作用,只是映射
    SQUARE:engines.NewSquare()
    ,但现在添加了闭包,将映射转化为一个只包含一个开关的函数看起来确实很简单。你知道哪一个函数的性能更好,以防我在性能重要的环境中面临这一决定吗?差别很小。一如既往,但只有在必要时才会如此。
    var engine gameEngine
    
    var newGameFuncs = map[GameMode]func() gameEngine {
        SQUARE:   func() gameEngine { return engines.NewSquare() },
        TRIANGLE: func() gameEngine { return engines.NewTriangle() },
    }
    
    func JoinGame(mode GameMode) (int, error) {
        engine = newGameFuncs[mode]()
        id, err := engine.AddPlayer()
        // Some other stuff, too
        return id, nil
    }