1 回答
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 不会“涵盖”。
- 1 回答
- 0 关注
- 155 浏览
添加回答
举报