【Go】値オブジェクト(Value Object)を生成する。
値オブジェクト(Value Object)は値そのものを表すオブジェクトです。
今回は、ドメイン駆動設計入門の内容を参考にGo言語でEmailAddress
を題材にサンプルコードを書きます。
良書なので詳しい内容は書籍を購入しご確認ください。
値オブジェクトの特徴
値オブジェクトの特徴としては以下3点が挙げられます。
- 不変である。
- 交換が可能である。
- 等価性によって比較される。
不変である
値は不変な性質を持っています。
0
という値がある日突然1
になったらどうでしょうか?
値を変えるということは今まで0
として扱っていた値を1
として扱うことと同じです。
値は不変であることで安心して利用することができます。
値を変更してしまうコード
値を変更するコードを書くことはできます。
以下はemailAddress
という値を書き換えるサンプルコードです。
.
├── domain
│ └── email.go
├── go.mod
└── main.go
func main() {
emailAddress := domain.NewEmailAddress("test@test.com")
emailAddress.ChangeAddress("aaa@test.com")
fmt.Println(emailAddress.GetAddress())
}
package domain
type EmailAddress struct {
address string
}
func NewEmailAddress(address string) *EmailAddress {
return &EmailAddress{address: address}
}
func (e *EmailAddress) ChangeAddress(address string) {
e.address = address
}
func (e EmailAddress) GetAddress() string {
return e.address
}
aaa@test.com
上記のコードは次のような書き方と同じです。
func main() {
0.ChangeNumber(1)
fmt.Println(0)
// => 1
0
という値を1
で書き換えています。
0
前提でプログラムコードを書いていた場合、突然オブジェクトの値が1に書き換えられたらバグの原因になるのは明らかです。
このようにオブジェクトの状態を書き換えるのはバグの原因になるため、不変なオブジェクトとして扱うことによってバグのリスクを軽減することができます。
不変であるデメリット
一方、可変にした場合は値を変更するたびに新しいインスタンスを生成する必要があり、コストがかかります。
交換が可能である
不変の性質を持つ値はそれ自体を変更することができません。しかし、代入によって交換することができます。
// 数字の変更
num := 0
num = 1
// アドレス変更
emailAddress := domain.NewEmailAddress("test@test.com")
emailAddress = domain.NewEmailAddress("aaa@test.com")
等価性によって比較される
値同士は比較することができるように、値オブジェクトも比較することができます。
// 値同士の比較
fmt.Println(0 == 0)
// 値オブジェクト同士の比較
emailAddressA := domain.NewEmailAddress("test@test.com")
emailAddressB := domain.NewEmailAddress("test@test.com")
fmt.Println(emailAddressA.Equal(emailAddressB))
func (e *EmailAddress) Equal(other *EmailAddress) bool {
return e.address == other.address
}
値オブジェクトとして扱う基準
本書の中では以下2点が値オブジェクトとして扱う基準として挙げられています。
- そこにルールが存在しているか
- それ単体で取り扱いたいか
メールアドレスという値に関して考えたら「@」を含むというルールが存在します。また、大学生向けのサービスであればドメインにac.jp
というルールが存在するかもしれません。
値オブジェクトにすることによってドメインの中で値がどれくらい重要なルールを持つかを適宜判断する必要があります。
参考
Discussion