4

私は通常、戦略を実装するために特性を使用します (付随するフィールドを必要としないアクション)。最近、同じ機能がオブジェクトに関して定義されている可能性があることを発見しました。Function トレイトを直接拡張するか、apply() 以外の特別なメソッドを定義するいくつかのトレイトを拡張します。

コード例:

/* strategy realization via traits */
package object Traitness {
  trait Strategy {
    def performAction() : Unit = ()
  }
  abstract class Usage {_ : Strategy =>
  def doWork() =
    this.performAction()
  }

  // defining strategies
  trait SayA extends Strategy {
    override def performAction() = {
      println("A")
      super.performAction()
    }
  }

  trait SayB extends Strategy {
    override def performAction() = {
      println("B")
      super.performAction()
    }
  }

  trait SayC extends Strategy {
    override def performAction() = {
      println("C")
      super.performAction()
    }
  }

  //using strategies
  class SimpleStrategy extends Usage with SayA
  def reverseOrder() = new Usage with SayC with SayA
  object fullUsage extends Usage with SayA with SayB with SayC

  //run-time checking
  val check1 : Boolean = (new SimpleStrategy).isInstanceOf[SayB]
  val check2 : Boolean = reverseOrder().isInstanceOf[SayB]
  val check3 : Boolean = fullUsage.isInstanceOf[SayB]

  //compile-time checking
  def proclaim(x : SayB) = println("SayB")
}

/* strategy realization via function objects */
package object Valueness {
  trait Strategy extends Function0[Unit]

  class Usage(val strategies : List[Strategy]) {
    def doWork() = for (s <- strategies)
      s()
  }

  //defining strategies
  object SayA extends Strategy {
    override def apply() = {
      println("A")
    }
  }

  object SayB extends Strategy {
    override def apply() = {
      println("B")
    }
  }

  object SayC extends Strategy {
    override def apply() = {
      println("C")
    }
  }

  //using strategies
  class SimpleStrategy extends Usage(SayA :: Nil)
  def reverseOrder() = new Usage(SayB :: SayA :: Nil)
  val fullUsage = new Usage(SayA :: SayB :: SayC :: Nil)

  //run-time checking
  def check(strategy : Strategy, usage : Usage) = usage.strategies contains strategy
  val check1 : Boolean = check(SayB, new SimpleStrategy)
  val check2 : Boolean = check(SayB, reverseOrder())
  val check3 : Boolean = check(SayB, fullUsage)

  //no compile-time checking available
}

どちらを選ぶべきですか?

4

2 に答える 2

4

あなたが説明したユースケースでは、特性またはオブジェクトのいずれかを使用することは、不必要なオブジェクト指向のやり過ぎです。あなたの戦略は単なる関数であり、そのように最もきれいに実装できます。

object Strategy{

  type Strategy = () => Unit

  val sayA:Strategy = ()=>{println("A")}
  val sayB:Strategy = ()=>{println("B")}
  val sayC:Strategy = ()=>{println("C")}
}

ここで Function0[Unit] のサブクラスを作成しても何も得られず、単純なリテラルを作成する能力が犠牲になります。関数は、Scala では完全に優れたエンティティです。それらに慣れ、ためらわずに直接使用してください。

于 2012-12-01T19:25:52.763 に答える
0
class MyStrategy {
  val sayABC: Strategy.Strategy = () => {
    Strategy.sayA()
    Strategy.sayB()
    Strategy.sayC()
  }
}
reflect.runtime.universe.typeOf[MyStrategy].members.filter(_.asTerm.fullName.endsWith(".sayABC")).head

結果:

res36: reflect.runtime.universe.Symbol = value sayABC

私の関数 sayABC が異なる関数の呼び出しだけで構成されている場合、AST 経由で sayA、sayB、sayC への呼び出しを取得する方法を誰かが教えてくれたらいいのにと思います。

... Dave Griffith のコードに対する整形式の回答を意図しています。

于 2012-12-01T20:52:26.560 に答える