sealed abstract case classがすごい
sealed abstract case classなるものがある。別のことを調べてたらこちらの記事(のコメント欄)で見掛けて感動してしまった。
軽く触れると、newできなくなり、case classによって自動で生成されるcopyメソッド、そしてコンパニオンオブジェクトのapplyメソッドが生成されなくなる、というもの。その上でcase classの他の特性を持つ。
これ、インスタンスの生成に関する手段のみが綺麗に潰されているので、バリデーションを挟むファクトリだったりを強制できるのが嬉しい。
私自身は今まで以下のようにしていた。
trait Person { def name: String def age: Int } private case class PersonImpl(name: String, age: Int) extends Person object Person { def apply(name: String, age: Int): Person = { // ... PersonImpl(name, age) } }
こんな風にtraitでインタフェースのみ定義し、その実装をcase classにする。これでequalsメソッドなどは自動で定義してくれる。で、traitの方のコンパニオンオブジェクトで生成してあげる。もちろん実装であるcase class自体は隠しちゃう。
しかしこれ、unapplyメソッドなどは自前で定義しなくちゃならないし、toStringメソッドは実装クラス(この場合はPersonImpl)のものなので、想定した結果にならないと、微妙なとこもあった。
ので、まあケースに応じはするわけだが、sealed abstract case classは有用そうだなと思う。