Scala DSL - 嵌套块引用父级

时间:2013-01-30 15:15:02

标签: scala dsl

在Scala中使用DSL,所以我可以说我有类似的东西:

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

现在我想要的是在每个嵌套块中它有一个引用或在封闭块上引用函数。例如,效果是地板被添加到房屋,卧室到地板等。

目前,我以一种可怕的方式执行此操作,即在每个嵌套级别更新全局堆栈以跟踪当前的“上下文”。此外,我当前的版本不是类型安全的,因为我可以在房子里添加卧室。

另一个先前的修订是

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

每个块返回一个窗口小部件列表(+使用隐式将一般的“事物”转换为“事物列表”,以便可以添加下一个“事物”)。然后在块返回后添加返回的小部件列表。但是我不喜欢强制使用+,因为它在很多页面上都很难看。

无论如何要融合这两个人?

2 个答案:

答案 0 :(得分: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))

将常见行为分解为某些基本特征或方法应该相当容易,例如,迭代子组件以修复关系。

答案 1 :(得分: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
  }
}