Kotlinでバリューオブジェクトを書く
バリューオブジェクトとは
イメージは下記の方の記事がわかりやすいかと思います。
私なりの言葉でいうと以下のよう言葉になります。
業務(ドメイン)に出てくる値的(データ)概念を独自のクラスとして表現したもの
わざわざそれを用意するメリットは前述記事の中で十分言及されていますので是非読んでみてください。
加えて、個人的には値の参照を追尾できるというメリットがあると思っています。
プリミティブで表現されたあるデータは実装者ごとに名称にバラつきが出た時点で参照箇所を正確に把握することは困難になってしまう一方で、決まったクラス(型)で常に表現されていれば、その型の参照を追えばどこでそのデータが使われる可能性があるのかを簡単に追跡できます。(これは改修作業等の際の大きなアドバンテージだと思います。)
実装例
値をひとつだけもつバリューオブジェクト(Java.Ver)
@Value(staticConstructor = "of")
public class Name {
@NonNull
String value;
}
値をひとつだけもつバリューオブジェクト(Kotlin.Ver)
kotlin 1.5よりvalue class
という言語仕様が追加されておりこれを使うことでとてもシンプルに表現することができます。
(もともとinline class
と呼ばれていたものがExperimental/Betaを経てStableになって名称変更されたみたいです。)
@JvmInline
value class Name(val value: String)
value class
自体の特徴
- 単一のプロパティ
- そのプロパティはイミュータブル(val宣言されてなければならない)
- 参照比較(===)は使えない
data class
というものに非常に似ていますが以下の違いがあります。
実際のクラスを生成するのではなくて、バイトコードとしては通常通り内部のプロパティの型で扱うことでオーバーヘッドが少ない模様です。
値を複数もつバリューオブジェクト(Java.Ver)
@Value(staticConstructor = "of")
@NonNull
public class User {
Name name;
Age age;
}
値を複数もつバリューオブジェクト(Kotlin.Ver)
こちらは複数のプロパティを持つ必要性があるので、通常のイミュータブルなデータを扱えるdata class
での実装が望ましいと思っています。
data class User(val name: Name, val age: Age)
まとめ
プリミティブをラップしたベースになるようなバリューオブジェクトはvalue class
で書くことで満たすべき性質や思想に反するような操作をコンパイラーが抑制してくれるのでとても便利だと思いました。
参考
Discussion