首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >什么是与Java构建器模式等效的Scala?

什么是与Java构建器模式等效的Scala?
EN

Stack Overflow用户
提问于 2011-01-07 20:46:09
回答 4查看 31.6K关注 0票数 61

在我每天用Java语言做的工作中,我经常使用构建器来实现流畅的接口,例如:new PizzaBuilder(Size.Large).onTopOf(Base.Cheesy).with(Ingredient.Ham).build();

通过一种快捷的Java方法,每个方法调用都会改变构建器实例并返回this。不可改变的是,它涉及更多的类型,在修改之前首先克隆构建器。build方法最终在构建器状态上执行繁重的任务。

在Scala中实现相同目标的好方法是什么?

如果我想确保onTopOf(base:Base)只被调用一次,然后只有with(ingredient:Ingredient)build():Pizza可以被调用,就像定向构建器一样,我该如何处理这个问题呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-01-07 21:08:32

Scala2.8中Builder模式的另一个替代方案是使用具有默认参数和命名参数的不可变case类。它有一点不同,但效果是聪明的默认值,所有指定的值和语法检查只指定一次的东西…

下面的代码使用字符串表示简洁/速度的值...

scala> case class Pizza(ingredients: Traversable[String], base: String = "Normal", topping: String = "Mozzarella")
defined class Pizza

scala> val p1 = Pizza(Seq("Ham", "Mushroom"))                                                                     
p1: Pizza = Pizza(List(Ham, Mushroom),Normal,Mozzarella)

scala> val p2 = Pizza(Seq("Mushroom"), topping = "Edam")                               
p2: Pizza = Pizza(List(Mushroom),Normal,Edam)

scala> val p3 = Pizza(Seq("Ham", "Pineapple"), topping = "Edam", base = "Small")       
p3: Pizza = Pizza(List(Ham, Pineapple),Small,Edam)

然后,您也可以使用现有的不可变实例作为某种构建器…

scala> val lp2 = p3.copy(base = "Large")
lp2: Pizza = Pizza(List(Ham, Pineapple),Large,Edam)
票数 59
EN

Stack Overflow用户

发布于 2013-04-30 13:27:03

Case类解决了上述问题,但是当您的对象中有scala集合时,很难在java中使用生成的api。要向java用户提供流畅的api,请尝试执行以下操作:

case class SEEConfiguration(parameters : Set[Parameter],
                               plugins : Set[PlugIn])

case class Parameter(name: String, value:String)
case class PlugIn(id: String)

trait SEEConfigurationGrammar {

  def withParameter(name: String, value:String) : SEEConfigurationGrammar

  def withParameter(toAdd : Parameter) : SEEConfigurationGrammar

  def withPlugin(toAdd : PlugIn) : SEEConfigurationGrammar

  def build : SEEConfiguration

}

object SEEConfigurationBuilder {
  def empty : SEEConfigurationGrammar = SEEConfigurationBuilder(Set.empty,Set.empty)
}


case class SEEConfigurationBuilder(
                               parameters : Set[Parameter],
                               plugins : Set[PlugIn]
                               ) extends SEEConfigurationGrammar {
  val config : SEEConfiguration = SEEConfiguration(parameters,plugins)

  def withParameter(name: String, value:String) = withParameter(Parameter(name,value))

  def withParameter(toAdd : Parameter) = new SEEConfigurationBuilder(parameters + toAdd, plugins)

  def withPlugin(toAdd : PlugIn) = new SEEConfigurationBuilder(parameters , plugins + toAdd)

  def build = config

}

这样,在java代码中,api就非常容易使用。

SEEConfigurationGrammar builder = SEEConfigurationBuilder.empty();
SEEConfiguration configuration = builder
    .withParameter(new Parameter("name","value"))
    .withParameter("directGivenName","Value")
    .withPlugin(new PlugIn("pluginid"))
    .build();
票数 13
EN

Stack Overflow用户

发布于 2011-01-07 20:53:00

这是完全相同的模式。Scala允许突变和副作用。也就是说,如果你想更纯粹,让每个方法返回你正在构造的对象的一个新实例,这个对象的元素已经改变了。您甚至可以将函数放在类的对象中,以便在代码中有更高级别的分离。

class Pizza(size:SizeType, layers:List[Layers], toppings:List[Toppings]){
    def Pizza(size:SizeType) = this(size, List[Layers](), List[Toppings]())

object Pizza{
    def onTopOf( layer:Layer ) = new Pizza(size, layers :+ layer, toppings)
    def withTopping( topping:Topping ) = new Pizza(size, layers, toppings :+ topping)
}

以使您的代码看起来像这样

val myPizza = new Pizza(Large) onTopOf(MarinaraSauce) onTopOf(Cheese) withTopping(Ham) withTopping(Pineapple)

(注意:我可能在这里搞错了一些语法。)

票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4625580

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档