为了账号安全,请及时绑定邮箱和手机立即绑定

嵌入golang是否违反了德米特法则?

嵌入golang是否违反了德米特法则?

Go
慕丝7291255 2021-11-15 20:35:09
这就是Effective GO关于嵌入在 golang 中所说的话当我们嵌入一个类型时,该类型的方法成为外部类型的方法,但是当它们被调用时,方法的接收者是内部类型,而不是外部类型我有一个代码片段,其中Struct User定义如下type User struct {    Name     string    Password string    *sql.Tx}然后我打电话给u.Query("some query here")等等。我专门做了这个,这样我就可以避免这样的电话u.Transaction.Query("query"),这显然违反了迪米特法则。现在,在阅读了文档和有效的 go 之后,我也怀疑第一种方法的优点。我是否违反了得墨忒耳定律?如果是,我该如何避免?
查看完整描述

1 回答

?
慕容708150

TA贡献1831条经验 获得超4个赞

嵌入概念在某种程度上违反了迪米特法则,因为如果类型本身被导出,它不会隐藏类型被嵌入的事实。请注意,嵌入未导出的类型不会违反 LoD(您不能引用未导出的字段和方法)。


但这并不强制您以同样违反 LoD 的方式引用提升的字段或方法。嵌入本身只是一种技术,因此您可以将通用的共享代码“外包”给其他类型;或者从另一个角度来看,在创建新类型时使用其他类型。您引用嵌入类型的提升字段或方法的方式可能违反法律。


正如您所说,如果您将其称为u.Tx.Query(),则明显违反了迪米特法则:您正在使用User嵌入的实现细节*sql.Tx。


但如果你这样称呼它:u.Query()那没问题。这种形式不会暴露或利用*sql.Tx嵌入的事实。如果实现发生变化,此表单将继续工作并且*sql.Tx不再嵌入(例如,它被更改为“常规”字段或完全删除,并User.Query()添加了一个方法)。


如果您不想允许访问导出的嵌入类型的字段值,请将其设为未导出的常规字段并添加一个User.Query()可以委托给该字段的“显式”方法,例如:


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()使用了 ,则使用 this 的客户端在 的内部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 不会“涵盖”。


查看完整回答
反对 回复 2021-11-15
  • 1 回答
  • 0 关注
  • 155 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信