Architecture 在Go中存储状态

Architecture 在Go中存储状态,architecture,go,coding-style,global-variables,information-hiding,Architecture,Go,Coding Style,Global Variables,Information Hiding,我正在用围棋写一个简单的程序,作为学习围棋语言的练习。该程序是一个游戏玩家:它exec.Commands是一个基于文本的游戏,然后通过StdinPipe/StdoutPipe与之通信。经过一番胡闹和阅读大量在线文档后,我成功地使框架工作起来——相当于Hello World,在那里我建立了双向通信,可以处理程序终止等错误 现在我正在尝试编写实际的游戏AI代码。因为我的目的是学习这门语言,所以我在风格上非常谨慎——我不想只想用围棋写C(或其他语言) 程序中明显的分工(一旦所有设置完成)分为两部分。首

我正在用围棋写一个简单的程序,作为学习围棋语言的练习。该程序是一个游戏玩家:它
exec.Command
s是一个基于文本的游戏,然后通过
StdinPipe
/
StdoutPipe
与之通信。经过一番胡闹和阅读大量在线文档后,我成功地使框架工作起来——相当于Hello World,在那里我建立了双向通信,可以处理程序终止等错误

现在我正在尝试编写实际的游戏AI代码。因为我的目的是学习这门语言,所以我在风格上非常谨慎——我不想只想用围棋写C(或其他语言)

程序中明显的分工(一旦所有设置完成)分为两部分。首先,程序查看当前状态并决定应该向游戏发出什么命令。其次,程序查看返回的数据并相应地更新状态。(是的,这是一个简单的游戏——它等待输入,然后响应,没有时间问题。)

我不确定这些州信息应该放在哪里。将其全部转储到全局范围感觉是错误的,而创建一个庞大的单例对象似乎更糟糕(Go并不是特别的OO)。在任何情况下,我都不想让函数传递并返回20多个变量

一般的建议很好,但我最感兴趣的是什么在习惯上适合围棋。根据请求,我可以共享代码,但我认为这不会有什么帮助。

Go确实启用了一个


为游戏状态创建结构类型。在程序中传递一个指向这种类型的值的指针,或者将指针存储在包级别变量中(如果这类事情不困扰您的话)。根据需要在此类型上实现方法。考虑将它放入自己的包中进行更大的封装。

< P>我喜欢使用这个程序包。

简单的例子:

package foo

func Incr() {
    f.incr()
}

func Count() int {
    return f.count()
}

type foo struct {
    sync.RWMutex
    count int
}

func (f *foo) incr() {
    f.Lock()
    f.count++
    f.Unlock()
}

func (f *foo) count() int {
    f.RLock()
    defer f.RUnlock()
    return f.count
}

var f = &foo{}

此包可以导入到任何其他包并保持状态。我添加了sync.RWMutex以防止任何竞争条件。这使您能够完全控制如何访问foo的状态,并且可以很好地控制它。

谢谢您的回答。如果你不介意的话,我会等到明天再接受答案——我还在考虑什么样的解决方案最好。(+1)谢谢。让我确保我理解你的建议:我创建一个
struct
,它保存所有状态变量,然后将其实例化为一个全局对象,以便在更新函数中检查和修改状态。对的(当然,我对你也是一样。)@Charles,没错。您可以在结构上存储所需的任何状态,如果愿意,还可以向该结构添加方法。这种方法的优点是,您可以完全控制访问并轻松地将状态导入其他包。Go的net/http包采用与HandlerFunc和Handler方法类似的方法,允许您在多个包中添加http处理程序。@tommywild您能详细说明一下吗?添加foo_测试和测试包中的任何内容都非常容易。您还可以使用导出的方法轻松测试上述功能。@tommywild我明白您的意思。我编辑了答案,所以foo有一个incr和count方法,这将允许对foo进行独立于f状态的测试。@tommywild我简单地删除了这个答案,考虑了一会儿,现在正在取消删除它。我的理性:在游戏(或大多数程序)中,你需要某种方式来维持状态。上述方法允许线程安全地访问游戏状态,并允许程序的任何部分轻松访问所述状态,而无需将状态传递给每个函数。我认为这种方法应该谨慎使用,但一定程度的实用主义会起到很大作用。