エクスポートされていない構造体ポインタの埋め込み
エクスポートされた構造体がエクスポートされていない構造体ポインタを埋め込む
外部パッケージから構造体を任意に生成することを防ぎ、
必ず定められたコンストラクタや検証ロジックを経由するように強制します。
例
1type completedConfig struct {
2 Options options.CompletedOptions
3 Aggregator aggregatorapiserver.CompletedConfig
4 KubeAPIs controlplane.CompletedConfig
5 ApiExtensions apiextensionsapiserver.CompletedConfig
6
7 ExtraConfig
8}
9
10type CompletedConfig struct {
11 // Embed a private pointer that cannot be instantiated outside of this package.
12 *completedConfig
13}
Goalコンストラクタの強制 (Enforced Constructor)
- 外部パッケージから構造体リテラル(Struct Literal)を介してオブジェクトを任意に生成または変更することを防止
- 外部パッケージでは、エクスポートされていないフィールドを持つ構造体をリテラルで生成(初期化)することはできません
- ファクトリメソッドの強制
- オブジェクトが生成される前に、必須のバリデーション(Validation)やデフォルト値の設定(Defaulting)が完了していることを保証
一般的なカプセル化
1type CompletedConfig struct {
2 // フィールドがエクスポートされていないため、外部パッケージからアクセス不可
3 options options.CompletedOptions
4 aggregator aggregatorapiserver.CompletedConfig
5}
- 外部から値を読み取ることができません
- すべてのフィールドに対してGetterメソッドが必要です
エクスポートされていないポインタの埋め込み
1type completedConfig struct { // unexported struct
2 Options options.CompletedOptions // Exported Field!
3 Aggregator aggregatorapiserver.CompletedConfig // Exported Field!
4}
5
6type CompletedConfig struct {
7 *completedConfig // 埋め込み
8}
- 外部からは、まるで自身のフィールドであるかのように
cfg.Optionsで直接アクセスが可能です。 - しかし、
CompletedConfig自体を生成({})しようとすると、*completedConfig型がエクスポートされていないため、リテラル初期化がブロックされます。
利点
- 生成制限 (Safety):
CompletedConfig{...}(構造体リテラル)で安易に作成することを防ぎます (コンストラクタ関数の強制)。- アクセス利便性 (Convenience): オブジェクトを使用する際、
cfg.GetOptions()のように面倒なメソッドを呼び出す代わりに、cfg.Optionsのように変数に直接アクセスが可能です (Getterメソッドの記述が不要)。
欠点
- 内部的にリフレクションを使用するライブラリの利用が困難になります。
- 単体テストコード作成時にMockやStubを作成するのが難しくなります。
誤った使用を根本的に防ぎ、ライブラリの安定性を高める必要がある
インフラオブジェクトやコアライブラリの設計時に使用を推奨します。