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

时间:2019-04-27 12:51:05

标签: go

该问题与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
)

在主软件包中定义此接口的原因主要有两个:

  1. 在使用该接口的同一文件中包含接口定义可以提高可读性。如果不确定某个对象的功能,可以滚动到接口定义并进行检查。
  2. 将接口定义放入package engines内,就像回到类明确声明其实现的接口的情况一样,其中一件事情是设计不需要的。

这意味着在引擎实现的文件中,例如Square.goTriangle.go,我无权访问该接口,并且相应的newFunction必须返回其各自的类型,这使得它们分别为func() *Squarefunc() *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函数注册在一个位置。

1 个答案:

答案 0 :(得分:0)

您宁愿定义一个新的类型(函数的别名),而不是一个接口。 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)
}