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
}