4

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

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

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

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

之前的另一个修订是

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

每个块返回一个小部件列表(+ 使用隐式将通用“事物”转换为“事物列表”,以便可以添加下一个“事物”)。一旦块返回,则添加返回的小部件列表。但我不喜欢强制使用 + ,因为它在许多页面上变得丑陋。

无论如何要融合两者?

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 回答