我有一个带有几个模块的项目。由于以下情况:
,我在循环导入方面有问题详细信息
模块游戏包含具有当前游戏状态的结构。另一个模块(修饰符)正在执行一些特定游戏的内容和计算,因此可以修改游戏状态。因此,修饰符将需要结构游戏,但不需要游戏中的任何方法。从游戏中调用修饰符,在这里我们有循环导入。
问题:
游戏启动修饰符
修饰符需要游戏结构
在我看来,这是一个常见的情况,所以我想知道如何以最好的方式解决它。我的解决方案是创建第三个模块"结构"。它只包含整个应用程序的所有结构。这是一个很好的解决方案吗?
带有第三软件包选项:
yourgame/
state/
state.go
modifier/
modifier.go
main.go
main.go
将两个组件粘合在一起:
import "yourgame/state"
import "yourgame/modifier"
type Game struct {
state state.State
modifier modifier.Modifier
}
func main() {
// something like:
var game Game
game.modifier.Modify(game.state)
}
这种方法可能太紧了。我不会操纵本质上是全球状态对象,而是尝试将数据切成修饰符所需的内容。
抽象的推理很难,因此这是我的意思的具体示例。在您的游戏中:
type Object struct {
ID, X, Y int
// more data here
}
type Game struct {
Objects map[int]*Object
}
在您的"修饰符"中,假设我们有一个移动对象的AI模块。如果他所关心的只是一个对象的位置,则可以创建一个接口:
// in yourgame/modifier
type Object interface {
GetCoordinates() (int, int)
SetCoordinates(int, int)
}
type Modifier struct {}
func (m *Modifier) Update(obj Object) { }
那么,我们只需要将这些方法添加到我们的原始对象:
type (obj *Object) GetCoordinates() (int, int) {
return obj.X, obj.Y
}
type (obj *Object) SetCoordinates(x, y int) {
obj.X, obj.Y = x, y
}
现在,您可以将对象传递给修饰符而无需循环依赖。
现在,如果您的"修改器"接口最终看起来与您的游戏对象几乎完全相同,那么第三个结构软件包可能是合理的,因此您并不总是重复自己。例如,考虑net/url
。
通常,如果软件包B
具有直接读取/修改A.Type
的代码,则该代码应在软件包A
中。至少需要直接访问的部分。
要在单独的软件包A
和B
之间拆分某些东西,您通常会尝试隔离可以访问A.Type
的API,该API可以表示为接口。然后B
将定义和使用此接口,并且A.Type
将实现它(隐式,无需包括B的定义)。
然后(可能是A
,可能是单独的软件包)将通过A.Type
或*A.Type
值适当地使用B
。
或取决于您的设计,可以逆转关系,B.OtherType
隐式实现了A
定义和使用的接口。或A
和B
都只能通过接口相互使用;这完全取决于细节。
例如。也许类似:
package Game // "A"
type State struct {
data int // etc
}
func (s State) IsValid() bool { return true }
func (s *State) ChangeY(arg int) error { return nil }
// …etc…
和:
package Modifier // "B"
type GameState interface {
IsValid() bool
ChangeY(int) error
}
type M struct {
s GameState
//…
}
func New(s GameState) *M {
return &M{s: s}
}
func (m M) DoSomething() {
if s.IsValid() {
// …
}
s.ChangeY(42)
// …etc…
}
我将定义类型(在这种情况下为游戏)及其所有方法在同一软件包中。您甚至无法根据语言规格从另一个软件包导入的类型定义方法,
//you should first do
type MyPackageType ImportedType
//and only then
func (foo MyPackageType) Modify() {
...
}