🗳️

Kotlinでバリューオブジェクトを書く

2021/11/29に公開

バリューオブジェクトとは

イメージは下記の方の記事がわかりやすいかと思います。

https://qiita.com/wanko5296/items/8b470934cdc14f869a91#問題解決の方法--値オブジェクトを使ってみる-

私なりの言葉でいうと以下のよう言葉になります。

業務(ドメイン)に出てくる値的(データ)概念を独自のクラスとして表現したもの

わざわざそれを用意するメリットは前述記事の中で十分言及されていますので是非読んでみてください。
加えて、個人的には値の参照を追尾できるというメリットがあると思っています。
プリミティブで表現されたあるデータは実装者ごとに名称にバラつきが出た時点で参照箇所を正確に把握することは困難になってしまう一方で、決まったクラス(型)で常に表現されていれば、その型の参照を追えばどこでそのデータが使われる可能性があるのかを簡単に追跡できます。(これは改修作業等の際の大きなアドバンテージだと思います。)

実装例

値をひとつだけもつバリューオブジェクト(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
で書くことで満たすべき性質や思想に反するような操作をコンパイラーが抑制してくれるのでとても便利だと思いました。

参考

https://star-zero.medium.com/kotlinのvalue-class-27e865696f35

Discussion