Scala中的简单建造者模式

3
我正在实现一个非常简单的建造者模式,用于类似地图的容器:
trait KeyValueContainer[K,V] {
  private var props: Map[K, V] = new HashMap[K, V]
  private var built = false

  /**
   * Adds a key/value pair
   */
  def +=(key: K, value: V): KeyValueContainer[K,V] = {
    if (built)
      throw new BuilderException

    props = props + (key -> value)
    this
  }

  def build = {
    built = true
    this
  }
}

class MyContainer extends KeyValueContainer[String, Double]

当在“new MyContainer()”上使用上述“+=”或“build”方法时,结果在两种情况下都是类型为KeyValueContainer [String,Double]的。我很确定过去某个地方曾经提到过可以以某种方式使其返回实际的MyContainer子类型。您会使用方法返回类型协变来实现这一点(类似于Java),还是在您看来有更安全/更好的解决方案?谢谢!
3个回答

1
这里是它:

http://docs.scala-lang.org/overviews/core/architecture-of-scala-collections.html

该模式依赖于编译时隐式解析的方式。基本上,如果作用域中存在多个隐式值,编译器会选择最具体的一个(在您的情况下,是您需要的子类型构建器)。
通过这种方式,您可以在基类中进行通用实现,并通过隐式参数获取子类构建器。
以下是我在自己项目中所做的示例:

https://gist.github.com/hejfelix/8a0270855d498d7981f9

另一个重要的方面是显式的自类型化,详情请参见http://www.scala-lang.org/node/124

1
这里不需要如此复杂的结构,换句话说,在这种情况下不需要隐式。F-bounded polymorphism就可以了。与标准库中使用CanBuildFrom的地方相比,关键区别在于,在这种情况下,结果类型应始终与原始集合相同。 - Régis Jean-Gilles
使用def build: this.type = { ... }来构建我的简单构建器。感谢所有额外链接的阅读材料。+1 - Nikolaos
1
Regis> 哦,是的,你说得对。我猜现在学习它也无妨,但如果他想走这条路,他可能(在某个时候)会使用像map或sth这样的转换。 Nikolaos> 我很高兴你从中获得了一些有用的东西 :) - Felix

0

-1

我推荐这篇文章,它更简单明了,重点突出:

建造者模式

通过使用 this.type,您可以返回自身并在此基础上构建。

trait PaginationParameters extends Parameters {
 var _pageSize: Option[Int] = None
 var _page: Option[Int] = None

 def pageSize(newPageSize: Int): this.type = {
  _pageSize = Some(newPageSize); this
 }

 def page(newPage: Int): this.type  = {
  _page = Some(newPage); this
 }

 override def parameters = super.parameters ++
        _pageSize.map("page-size" -> _) ++
        _page.map("page" -> _)
 }
}

干杯


你能为不可变数据结构做些什么吗? - Felix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接