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

问题描述 投票:2回答:1

这个问题与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,我无法访问接口,相应的new-Functions必须返回它们各自的类型,这使得它们分别为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函数。
go
1个回答
0
投票

您宁愿定义一个新类型(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)
}
© www.soinside.com 2019 - 2024. All rights reserved.