7

タイプがランタイム データによって決定されるオブジェクト インスタンスを作成したい:

trait Business
case class Business1() extends Business 
case class Business2() extends Business

object Business {
  def fromData(data:Array[Byte]): Business = data(0) match {
    case 1 => new Business1
    case 2 => new Business2
    case _ => throw new RuntimeException("data error")
  }
}

上記のコードは機能しますが、閉じられているという問題があります。新しいサブクラスを実装するたびに、コードBusinessを変更する必要があります。Business.fromData

case 3 => new Business3

登録せずに、Business.fromData一度定義して後で追加するにはどうすればよいですか?Business3Business4

編集

Multimethodこれが の完全な使用例、つまり、何らかの引数の関数に基づくディスパッチであることに最終的に気付きました。したがって、より一般的な質問は「scala で multimethod を実行する方法」である必要があります。私は、デザインパターンは言語能力がないためにのみ存在すると信じています。そのため、工場ベースの回答を受け入れることに消極的です。

4

4 に答える 4

3

これで問題は解決しませんがBusiness、「封印された」特性を作成すると、更新するまで、コンパイラは非網羅的な一致をキャッチしますfromData:

sealed trait Business
case class Business1() extends Business
case class Business2() extends Business

biz match {
    case Business1 => println("Business1")
}

...結果は...

warning: match is not exhaustive!
missing combination            Business2
于 2012-12-02T06:22:33.377 に答える
3

これを行うこともできます。それが一致するケースよりも優れているかどうかはわかりませんが。あなたがしようとしていることに依存します。

class Business {
  override def toString = "Business"
}

val factories: Map[Int, () => Business] = Map(
  1 -> (() => new Business {
    override def toString = "Business1"
  }),
  2 -> (() => new Business {
    override def toString = "Business2"
  }),
  3 -> (() => new Business {
    override def toString = "Business3"
  })
)

object Business {
  def fromData(data: Array[Byte]): Business = factories(data(0))()
}

val b = Business.fromData(Array(1,1,2))
println(b)
于 2012-12-02T10:33:16.410 に答える
1

古典的な答えは、抽象ファクトリとも呼ばれる登録付きのファクトリを使用することです。

したがって、上記の階層を考えると、別の回答でここに示されているのと同じように「工場」マップを作成しますが、オブジェクト作成者の並列階層も作成し、起動時にそれらを登録します。

trait BusinessCreator {
  def createBusiness() : Business 
}
object BusinessCreator1() extends BusinessCreator {
  override def createBusiness() : Business = new Business1()

  factories += "1" -> this
}
//etc.

それを行うもう 1 つのより「Scalaish」な方法は、並列階層をスキップして、各クラスのコンパニオン オブジェクトからファクトリ オブジェクトにクリエーター関数を登録することですが、考え方は同じです。

于 2012-12-02T11:44:39.607 に答える
0

これはどうですか?

val factories = collection.mutable.Map(
  1 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business1"
    }
    override def apply() = single 
  }
  ,2 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business2"
    }
    override def apply() = single 
  }
  ,3 -> new Function0[Business] { 
    private[this] lazy val single = new Business {
      override def toString = "Business3"
    }
    override def apply() = single 
  }
)
于 2012-12-02T23:50:18.203 に答える