埋め込みの概念は、型自体がエクスポートされた場合に型が埋め込まれたという事実を隠さないため、デメテルの法則に多少違反します。エクスポートされていない型を埋め込んでも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()
が使用されている場合、これを使用しているクライアントは、 の内部User
が変更されても影響を受けません (u.Query()
昇格されたメソッドを示しているか、 のメソッドUser
、つまり: を示しているかは問題ではありませんUser.Query()
)。
変更した場合sql.Tx
、はい、u.Query()
もう有効ではない可能性があります。しかし、互換性sql.Tx
がないことはほとんどありません。また、あなたが変更されたパッケージの開発者であり、互換性のない変更を行っている場合、互換性のない変更に依存する他のコードを変更するのはあなたの責任です。そうする(適切に更新するu.Query()
)ことで、呼び出したクライアントはu.Query()
影響を受けず、クライアントは内部で何かが変更されたことを知る必要はありません。
これはまさに LoD が保証することu.Query()
です。LoD は悪いことではありません。落としてはいけません。従う原則を選択することはできますが、選択した原則が指示するすべてのことに常に従うのではなく、考えるべきです。u.Tx.Query()
User
u.Query()
もう 1 つクリアする必要があるのは、LoD には API 非互換の変更は含まれていないということです。それが提供するものは、従う場合、エンティティの「公開」面を使用するエンティティの内部変更が他のエンティティに影響を与えないことです。sql.Tx
が大幅に変更されて利用できなくなった場合Tx.Query()
、それは LoD で「カバー」されません。