嵌入golang是否违反了demeter的规律?

时间:2015-10-20 09:10:22

标签: oop go struct embedding law-of-demeter

这是有效GO 在golang中嵌入所说的

  

当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但是当它们被调用时,方法的接收者是内部类型,而不是外部类型

我有一个代码段,其中Struct User定义如下

type User struct {
    Name     string
    Password string
    *sql.Tx
}

然后我打电话给u.Query("some query here")等我已经专门做了这个,这样我就可以避免像u.Transaction.Query("query")那样明显违反 Demeter法则的电话。现在,在阅读了文档和有效的文章后,我对第一种方法的优点也表示怀疑。 我是否违反了 Demeter法?如果是,我该如何避免呢?

1 个答案:

答案 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不会“覆盖”。