Scala:メソッドのポリモーフィズム

[scalaの多相いろいろ - おみブロZ](http://akiomik.hatenablog.jp/entry/2013/12/14/214929)という素晴らしい記事を参考に、メソッドのポリモーフィズムの実装パターンを自分なりにまとめてみる。

まず、「メソッドのポリモーフィズム」という言葉が一般的でないかもしれないので、この記事での意味として、「引数や戻り値の型が異なる同名のメソッドを実装する方法」としておく。

また、ここで例示する記事は、[GitHubのsuin/scala-playground](https://github.com/suin/scala-playground/blob/master/src/main/scala/playground/basic/Polymorphism.scala)に置いてあるので、試したい方はgit pullしてみてください。

## メソッドのオーバーロード

オーバーロードはJavaなどにもある仕組みで、引数の型が違う場合、同じ名前のメソッドを定義できる。アドホック多相(Ad hoc polymorphism)。

```scala
case class CreateCommand()
case class UpdateCommand()

case class CreateResult(createOk: Boolean)
case class UpdateResult(updateOk: Boolean)

class CommandHandler {
  def handle(createCommand: CreateCommand): CreateResult = CreateResult(true)
  def handle(updateCommand: UpdateCommand): UpdateResult = UpdateResult(true)
}

val handler = new CommandHandler()
val result1: CreateResult = handler.handle(CreateCommand())
val result2: UpdateResult = handler.handle(UpdateCommand())
```

## 継承(Commandパターン)

オブジェクト指向言語で見かけるデザインパターン。サブタイプ多相(Subtype polymorphism)。

```scala
case class CreateCommand()
case class UpdateCommand()

case class CreateResult(createOk: Boolean)
case class UpdateResult(updateOk: Boolean)

trait CommandHandler[C, R] {
  def handle(command: C): R
}

class CreateCommandHandler extends CommandHandler[CreateCommand, CreateResult] {
  override def handle(command: CreateCommand): CreateResult = CreateResult(true)
}

class UpdateCommandHandler extends CommandHandler[UpdateCommand, UpdateResult] {
  override def handle(command: UpdateCommand): UpdateResult = UpdateResult(true)
}

def apply() = {
val handler1 = new CreateCommandHandler()
val handler2 = new UpdateCommandHandler()
val result1: CreateResult = handler1.handle(CreateCommand())
val result2: UpdateResult = handler2.handle(UpdateCommand())
```

## Pimp my Library Pattern

Scalaの暗黙の型変換を使って、クラスにメソッドを追加する方法。

```scala
case class CreateCommand()
case class UpdateCommand()

case class CreateResult(createOk: Boolean)
case class UpdateResult(updateOk: Boolean)

class CommandHandler

implicit class CreateCommandHandler(handler: CommandHandler) {
  def handle(command: CreateCommand): CreateResult = CreateResult(true)
}

implicit class UpdateCommandHandler(handler: CommandHandler) {
  def handle(command: UpdateCommand): UpdateResult = UpdateResult(true)
}

val handler = new CommandHandler()
val result1: CreateResult = handler.handle(CreateCommand())
val result2: UpdateResult = handler.handle(UpdateCommand())
```

## Magnet Pattern (implicit parameter)

型クラス + Dependent Method Types + implicit parameterで実現するMagnet Pattern。

```scala
case class CreateCommand()
case class UpdateCommand()

case class CreateResult(createOk: Boolean)
case class UpdateResult(updateOk: Boolean)

trait Command[A, R] {
  type Result = R
  def apply(command: A): Result
}

class CommandHandler {
  def handle[A, R](command: A)(implicit handler: Command[A, R]): handler.Result = handler(command)
}

implicit val createCommand = new Command[CreateCommand, CreateResult] {
  def apply(command: CreateCommand): Result = CreateResult(true)
}

implicit val updateCommand = new Command[UpdateCommand, UpdateResult] {
  def apply(command: UpdateCommand): Result = UpdateResult(true)
}

val handler = new CommandHandler()
val result1: CreateResult = handler.handle(CreateCommand())
val result2: UpdateResult = handler.handle(UpdateCommand())
```

## Magnet Pattern (implicit conversion)

型クラス + Dependent Method Types + implicit conversionで実現するMagnet Pattern。

```scala
import scala.language.implicitConversions

case class CreateCommand()
case class UpdateCommand()

case class CreateResult(createOk: Boolean)
case class UpdateResult(updateOk: Boolean)

trait CommandMagnet[R] {
  type Result = R
  def apply(): Result
}

implicit def createCommandHandler(createCommand: CreateCommand): CommandMagnet[CreateResult] = new CommandMagnet[CreateResult] {
  def apply(): Result = CreateResult(true)
}

implicit def updateCommandHandler(updateCommand: UpdateCommand): CommandMagnet[UpdateResult] = new CommandMagnet[UpdateResult] {
  def apply(): Result = UpdateResult(true)
}

class CommandHandler {
  def handle[T](magnet: CommandMagnet[T]): magnet.Result = magnet()
}

val handler = new CommandHandler()
val result1: CreateResult = handler.handle(CreateCommand())
val result2: UpdateResult = handler.handle(UpdateCommand())
```

## 参考

* [scalaの多相いろいろ - おみブロZ](http://akiomik.hatenablog.jp/entry/2013/12/14/214929)
* [Scala の Pimp my Library Patternについて - scalaとか・・・](http://d.hatena.ne.jp/xuwei/20110623/1308787607)
* [Scala 2.10.0 Dependent method types - CLOVER](http://d.hatena.ne.jp/Kazuhira/20130115/1358256049)
* [Scala2.10.0のDependent method typesと型クラスを組み合わせた『The Magnet Pattern』がヤバい件 - ( ꒪⌓꒪) ゆるよろ日記](http://yuroyoro.hatenablog.com/entry/2013/01/23/192244)
* [Scalaで型クラス入門 - still deeper](http://chopl.in/post/2012/11/06/introduction-to-typeclass-with-scala/)
* [How to be polymorphic in Scala](http://scala.org.ua/presentations/scala-polymorphism/#/)