这是有效GO 在golang中嵌入所说的
当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但是当它们被调用时,方法的接收者是内部类型,而不是外部类型
我有一个代码段,其中Struct User
定义如下
type User struct {
Name string
Password string
*sql.Tx
}
然后我打电话给u.Query("some query here")
等我已经专门做了这个,这样我就可以避免像u.Transaction.Query("query")
那样明显违反 Demeter法则的电话。现在,在阅读了文档和有效的文章后,我对第一种方法的优点也表示怀疑。
我是否违反了 Demeter法?如果是,我该如何避免呢?
答案 0 :(得分:6)
嵌入概念有点违反Law of Demeter,因为无法隐藏嵌入类型的事实如果类型本身导出< / em>的。请注意,嵌入未导出类型不会违反LoD(您无法引用未导出的字段和方法)。
但是并不强迫以同样违反LoD的方式引用提升的字段或方法。嵌入本身只是一种技术,因此您可以将常见的共享代码“外包”到其他类型;或者从另一个角度来创建新的类型时使用其他类型。您引用嵌入类型的推广字段或方法的方式可能违反法律。
正如您所说,如果您将其称为u.Tx.Query()
,则明显违反了 Demeter法:您正在使用User
嵌入*sql.Tx
的实施细节1}}。
但如果你这样称呼它:u.Query()
那没关系。此表单不会暴露或利用*sql.Tx
嵌入的事实。如果实施更改并且*sql.Tx
将不再嵌入(例如,它被更改为“常规”字段或完全删除,并且添加了User.Query()
方法),此表单将继续有效。
如果您不想允许访问导出的嵌入类型的字段值,请将其设为未导出的常规字段,并添加可以委托给该字段的“显式”User.Query()
方法,例如:< / p>
type User struct {
Name string
Password string
tx *sql.Tx // regular field, not embedded; and not exported
}
func (u *User) Query(query string, args ...interface{}) (*sql.Rows, error) {
return u.tx.Query(query, args...)
}
补充说明:
在示例中,如果使用u.Query()
,如果User
的内部更改,则使用此内容的客户端不会受到影响(如果u.Query()
表示提升的方法,则无关紧要它表示User
的方法,即:User.Query()
)。
如果sql.Tx
发生变化,是的,u.Query()
可能不再有效。但是不太可能发生不兼容的sql.Tx
。如果您是更改的软件包的开发人员,并进行了不兼容的更改,则您有责任更改依赖于不兼容更改的其他代码。这样做(正确更新u.Query()
)调用u.Query()
的客户端不会受到影响,客户端仍然不需要知道更改内容的内容。
这正是LoD所保证的:如果您使用u.Query()
而不是u.Tx.Query()
,如果User
在内部发生变化,则调用u.Query()
的客户端无需知道或担心这一点。 LoD并不是件坏事。你不应该放弃它。你可以选择你遵循的原则,但你也应该思考而不是按照所选择的原则一直遵守所有时间,不惜任何代价。
还有一件事需要澄清:LoD不涉及API不兼容的更改。它提供的是如果遵循,实体的内部变更将不会对使用该实体的“公共”面的其他实体产生影响。如果sql.Tx
以激烈的方式更改Tx.Query()
将不再可用,则LoD不会“覆盖”。