Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
2
Help us understand the problem. What are the problem?

More than 3 years have passed since last update.

@yoshiyoshifujii

ScalaでDomain層にFirst Class Collectionを作るときのテクニック(JSON)

悩み

Domain駆動設計を採用しており、Domain層をPOJO(ScalaだとPOSO?)に作りたいってなったら、First Class Collectionを作るにしても、なんやかんやで、mapとか使いたくなることが多い。

とはいえ、そこで、mapを使えるようにしたら、なんか負けた気がするので、ちょっとしたテクニックで回避してみた。

課題

SomethingEntity の集合を保持するFirst Class Collectionを想定する。

case class SomethingEntity(id: SomethingId)

case class SomethingEntities(value: Seq[SomethingEntity])

この SomethingEntitiesの保持しているデータを全部JSONにしたいとき、

somethingEntites.value.map { somethingEntity =>
  convertToJson(somethingEntity)
}

// convertToJsonで好きなJSONライブラリを使って変換するのを想定している

みたいな感じにしたら意味ないよねって前提。

First Class Collectionだから、そもそも、classは、

case class SomethingEntities(private val value: Seq[SomethingEntity])

って感じで、 private にする。

すると、

somethingEntites.value.map { somethingEntity =>
  convertToJson(somethingEntity)
}

のvalueが取れなくてコンパイルエラーになる。

convertToJson 部分はライブラリに依存するから、

case class SomethingEntities(private val value: Seq[SomethingEntity]) {
  def toJson: Seq[String] =
    value.map(v => convertToJson(v))
}

みたいな実装はできない。(あくまでPOSOにこだわるなら。ただし、JSONはDomainに依存させても良いじゃんって場合はぜんぜん良いと思う。)

解決策

うすいJsonWriter的なtraitを定義だけしておいて、実装はお任せ的なことにするといける。

trait SomethingEntitiesWriter[JSON] {
  def toJson(entity: SomethingEntity): JSON
}

これを宣言しておいて、

case class SomethingEntities(private val value: Seq[SomethingEntity]) {
  def toJson[JSON](implicit writer: SomethingEntitiesWriter[JSON]): Seq[JSON] =
    value.map(writer.toJson)
}

みたいな感じ。

こうしておいて、 SomethingEntitiesWriter を以下みたいに実装する。

implicit object SomethingEntitiesWriterImpl extends SomethingEntitiesWriter[String] {
  override def toJson(entity: SomethingEntity): String =
    convertToJson(entity)
}

// convertToJsonで好きなJSONライブラリを使って変換するのを想定している

この implicit object をスコープに入れておいて、

somethingEntites.toJson[String]

と呼び出せば、良い感じに中のCollectionに直接アクセスしないで全部のEntityを Seq[String] にしてくれる感じが出来る。

このテクニック使えば、大体のことはいける気がする。

以上です。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
2
Help us understand the problem. What are the problem?