ScalaでChain of Responsibility

久しぶりにデザインパターンを読んだので、Scalaで気になったパターンを書いてみました。
自分用のメモです。

## Java言語で学ぶデザインパターン入門をそのままScalaにした版

Javaで書かれていたものをScalaにすると多分こんな感じ。
`var`を使わないように書いたのでJavaそのままではないけれども..

```scala
  case class Trouble(no: Int)

  trait Support {
    val name: String
    val next: Option[Support]

    def resolve(trouble: Trouble): Boolean
    def done(trouble: Trouble): Unit = println(s"$trouble is resolved by $name.")
    def fail(trouble: Trouble): Unit = println(s"$trouble cannot be resolved.")

    def support(trouble: Trouble): Unit =
      if (resolve(trouble)) done(trouble)
      else if (next.isDefined) next.get.support(trouble)
      else fail(trouble)
  }

  case class NoSupport(name: String, next: Option[Support] = None) extends Support {
    override def resolve(trouble: Trouble): Boolean = false
  }

  case class LimitSupport(name: String, limit: Int, next: Option[Support] = None) extends Support {
    override def resolve(trouble: Trouble): Boolean = trouble.no < limit
  }

  case class OddSupport(name: String, next: Option[Support] = None) extends Support {
    override def resolve(trouble: Trouble): Boolean = trouble.no % 2 == 1
  }

  case class SpecialSupport(name: String, number: Int, next: Option[Support] = None) extends Support {
    override def resolve(trouble: Trouble): Boolean = trouble.no == number
  }

  val fred = LimitSupport("Fred", 300, None)
  val elmo = OddSupport("Elmo", Some(fred))
  val diana = LimitSupport("Diana", 200, Some(elmo))
  val charlie = SpecialSupport("Charlie", 429, Some(diana))
  val bob = LimitSupport("Bob", 100, Some(charlie))
  val alice = NoSupport("Alice", Some(bob))

  (0 until 500 by 33).foreach(i => alice.support(Trouble(i)))
```

```
Trouble(0) is resolved by Bob.
Trouble(33) is resolved by Bob.
Trouble(66) is resolved by Bob.
Trouble(99) is resolved by Bob.
Trouble(132) is resolved by Diana.
Trouble(165) is resolved by Diana.
Trouble(198) is resolved by Diana.
Trouble(231) is resolved by Elmo.
Trouble(264) is resolved by Fred.
Trouble(297) is resolved by Elmo.
Trouble(330) cannot be resolved.
Trouble(363) is resolved by Elmo.
Trouble(396) cannot be resolved.
Trouble(429) is resolved by Charlie.
Trouble(462) cannot be resolved.
Trouble(495) is resolved by Elmo.
```

## Partial Functionで書いてみた版

多分こんな感じにすればいいのかな..

```scala
  def limitSupportPF(name: String, limit: Int): PartialFunction[Trouble, Unit] = {
    case Trouble(no) if no < limit =>
      done(name, Trouble(no))
  }

  def oddSupportPF(name: String): PartialFunction[Trouble, Unit] = {
    case Trouble(no) if no % 2 == 1 =>
      done(name, Trouble(no))
  }

  def specialSupportPF(name: String, limit: Int): PartialFunction[Trouble, Unit] = {
    case Trouble(no) if no == limit =>
      done(name, Trouble(no))
  }

  def noSupportPF: PartialFunction[Trouble, Unit] = {
    case Trouble(no) => fail(Trouble(no))
  }

  private def done(name: String, trouble: Trouble) = println(s"$trouble is resolved by $name.")
  private def fail(trouble: Trouble) = println(s"trouble cannot be rsolved.")

  val fredPF = limitSupportPF("Fred", 300)
  val elmoPF = oddSupportPF("Elmo")
  val dianaPF = limitSupportPF("Diana", 200)
  val charliePF = specialSupportPF("Charlie", 429)
  val bobPF = limitSupportPF("Bob", 100)
  val alicePF = noSupportPF

  val pf = bobPF orElse charliePF orElse dianaPF orElse elmoPF orElse fredPF orElse alicePF

  (0 until 500 by 33).foreach(no => pf(Trouble(no)))
```