ValueObjectの学習をしたので、そのアウトプットとして記載します。
1.ValueObjectとは
・日本語では、値オブジェクトとか記載されいてる。
・システムで利用される項目の条件を1つのオブジェクトにまとめたもの
・イミュータブル(変更不可)である。
2.なぜ必要なのか
なぜこのような面倒なことをする必要があるのか?普通にGetter/Setterを使えばいいじゃないか。と思ってしまいます。ちゃんと意味があり、ValueObjectが実装されています。その意味を以下に記載します。
①:型安全
各業務、各機能で利用されている項目は、全て入力される条件が存在しています。
その条件を無視して実装してしまえば、当然バグとなってしまいます。
その条件を1つにまとめ、データが生成される段階で、入力条件は全てクリアしている状態で作成されると、そのデータは、間違いなく正しいと言えます。
それが型安全となります。
※条件を他のコード(例えばServiceとか)に書けばいいじゃんと思うかもしれませんが、そうした場合、入力条件の判定分が、いろいろなコードに散らばってしまい、コードを変更しようとした場合、思わぬところでエラーが発生する可能性が出てきます。そうなると、品質が低下していしまいます。
②:データの不変性
各処理で作成されるデータは、すべて目的を持って作成されます。
データが変更される場合、作成された目的が異なるという事になります。
そのため、同じ変数を使い回すと、作成された目的が何か分からなくなってしまいます。
また、どこでそのデータが更新されたか、調査にも時間がかかるようになります。
3.実装
package main
import (
domain "VALUEOBJECT/domain"
"fmt"
)
func main() {
usercd, _ := domain.NewUsercd("TEST")
fmt.Println(usercd.Value())
}
package domain
import "errors"
type Usercd struct {
usercd string
}
// NewUsercdはUsercdのコンストラクタ
// データを登録する際は、この関数を使ってUsercdを生成する
func NewUsercd(usercd string) (Usercd, error) {
// ユーザーCDが空の場合はエラーを返す
if usercd == "" {
return Usercd{}, errors.New("usercd is required")
}
// ユーザーCDに禁則文字が含まれている場合はエラーを返す
if !check_forbidden_char(usercd) {
return Usercd{}, errors.New("usercd is required")
}
return Usercd{usercd: usercd}, nil
}
// UsercdはユーザーCDを返す
// Constructorで生成したUsercdの値を取得する
func (n Usercd) Value() string {
return n.usercd
}
// 禁則文字チェック
func check_forbidden_char(usercd string) bool {
if usercd == "***" {
return false
}
return true
}
※ちなみに、main.go内の変数:usercdに別の値を設定しようとすると、エラーとなります。
4.結果
実行した結果、以下のような回答がありました。
$ go run main.go
TEST
5.実行したコード
6.参考にしたサイト