这个问题与Golang function to return an Interface有关,并对其进行了扩展。
我的设置如下:
我正在创建一个游戏的服务器端,客户端可以选择不同的游戏模式。这些模式是通过不同的结构实现的,它们自己实现了一些方法,所有这些都是package engines
中自己的文件,例如:
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")
}
在主程序包中,当创建新游戏时,我使用地图来调用相应游戏模式的newSomething
函数。每个引擎都满足界面gameEngine
:
package main
import "engines"
type gameEngine interface {
AddPlayer() (int, error)
}
type GameMode int
const (
SQUARE GameMode = 0
TRIANGLE GameMode = 1
)
此接口在主程序包中定义,主要有两个原因:
package engines
中感觉就像回到类明确说明它们实现的接口的情况一样,其中一个设计并不需要。这意味着在我的引擎实现的文件中,如Square.go
和Triangle.go
,我无法访问接口,相应的new-Functions必须返回它们各自的类型,这使得它们分别为func() *Square
和func() *Triangle
类型(见上文) )。
现在我不能直接在map[GameMode]func() gameEngine
中使用这些新函数,因为它们的类型是错误的。我目前的解决方案是使用相当冗长的内联函数转换它们(受链接问题中的一个答案的启发):
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
}
这张地图感觉非常笨重和人为,但据我所知,这是用这种地图方法做到这一点的唯一方法。
有没有更好的方法或设计模式来实现我的目标?
func JoinGame(mode GameMode) (int, error)
是我的客户端界面的一部分,它是整个事物的起点,必须保持其签名。type gameEngine interface
应该留在主要包裹中。Hexagon.go
)时,唯一需要的步骤就是制作文件并在一个地方注册newHexagon
函数。您宁愿定义一个新类型(func的别名)而不是接口。 type AddPlayer func() (GameMode, error)
并使用engine
包中的函数封装此映射,您可以使用init()
在单独的文件中添加新的句柄函数(按需)。喜欢:engine/main.go
:
package engins
type GameMode int
const (
SQUARE = iota
TRIANGLE
)
type AddPlayer func() (GameMode, error)
var newGameFuncs = make(map[GameMode]AddPlayer)
func GetAddPlayerFuncByGameMode(gm GameMode) AddPlayer {
return newGameFuncs[gm]
}
engine/square.go
:
package engins
func init() {
newGameFuncs[SQUARE] = engineSquare{}.NewSquare
}
type engineSquare struct{}
func (engineSquare) NewSquare() (GameMode, error) {
return SQUARE, nil
}
从main.go
你可以像以下一样使用它:
package main
import e "./engins"
func main() {
e.GetAddPlayerFuncByGameMode(e.SQUARE)
}