4

Scala で DSL をいじっているので、次のようなものがあるとしましょう。

house {
  floor {
    bedroom("kids)
    bedroom("master")
  }
  floor {
    kitchen()
  }
}

今私が欲しいのは、ネストされた各ブロックで、参照を持っているか、囲んでいるブロックの関数を参照していることです。たとえば、床が家に追加され、寝室が床に追加されるなどの効果があります。

現在、私は現在の「コンテキスト」を追跡するために、ネストされた各レベルで更新されるグローバルスタックを持つという恐ろしい方法でこれを行っています。また、私の現在のバージョンは、家に寝室を追加できるという点でタイプセーフではありません。

別の以前のリビジョンは

house {
  floor {
    bedroom("kids) +
      bedroom("master")
  } +
    floor {
      kitchen()
    }
}

各ブロックがウィジェットのリストを返した場所 (+ は、次の「もの」を追加できるように、一般的な「もの」を「ものリスト」に変換する暗黙的なものを使用していました)。ブロックが返されると、返されたウィジェットのリストが追加されました。しかし、私は + を強制的に使用するのは好きではありません。

とにかく2つを融合するには?

4

2 に答える 2

2

このアプローチでは、関連するオブジェクトが作成された後、可変フィールドを使用して子と親の関係を設定します。

/* Data classes */

class House(val floors: Seq[Floor])
class Floor(val name: String, val bedrooms: Seq[Bedroom]) { var house: House = _}
class Bedroom(val name: String) { var floor: Floor = _ }

/* Factory methods */

def house(floors: Floor*) = {
  val house = new House(floors)
  floors foreach (_.house = house)
  house
}

def floor(name: String)(bedrooms: Bedroom*) = {
  val floor = new Floor(name, bedrooms)
  bedrooms foreach (_.floor = floor)
  floor
}

def bedroom(name: String) = new Bedroom(name)

これにより、次のように簡潔でタイプセーフな方法で家の構造を作成できます。

val myHouse = 
  house(
    floor("first")(
      bedroom("joe")
    ),
    floor("second")(
      bedroom("anna"),
      bedroom("clara")
    )
  )

assert(myHouse.floors(0).house == myHouse)
assert(myHouse.floors(1).house == myHouse)
assert(myHouse.floors(0).bedrooms(0).floor == myHouse.floors(0))
assert(myHouse.floors(1).bedrooms(1).floor == myHouse.floors(1))

関係を修正するためにサブコンポーネントを反復処理するなど、一般的な動作をいくつかの基本的な特性またはメソッドに組み込むのはかなり簡単なはずです。

于 2013-01-30T16:15:10.443 に答える
1

各ブロックに、囲んでいるブロックへの参照が本当に必要ですか? それとも、ネストされたブロックを親ブロックに追加できるようにするためでしたか? この場合、ネストされたブロックを囲んでいるブロックに単純に渡すことができます。

house (
  floor (
    bedroom("kids"),
    bedroom("master")
  ),
  floor (
    kitchen
  )
)

次の定義を使用します。

trait HouseElement
case class house( elements: HouseElement* )
trait FloorElement
case class floor( elements: FloorElement * ) extends HouseElement
case class bedroom( name: String ) extends FloorElement
case object kitchen extends FloorElement

それ以外の場合、別の解決策は匿名クラスに大きく依存することです (残念ながら、newどこでもキーワードを使用する必要があります)。

new house {
  new floor {
    new bedroom("kids")
    new bedroom("master")
  }
  new floor {
    new kitchen()
  }
}

次の定義を使用します。

import collection.mutable.Buffer
class house {
  val elements = Buffer[Element]()
  trait Element {
    elements += this 
  }        
  class floor extends Element { 
    val elements = Buffer[Element]()
    trait Element {
      elements += this 
    }        
    class bedroom(name: String) extends Element 
    class kitchen extends Element
  }
}
于 2013-01-30T15:48:57.780 に答える