什么是Scala等同于Java构建器模式?

在我日常使用Java进行的工作中,我使用了很多new PizzaBuilder(Size.Large).onTopOf(Base.Cheesy).with(Ingredient.Ham).build();接口的构建器,例如: new PizzaBuilder(Size.Large).onTopOf(Base.Cheesy).with(Ingredient.Ham).build();

一个快速和肮脏的Java方法,每个方法调用变异生成器实例,并返回this 。 毫无疑问,它涉及更多的打字,在修改之前先克隆建造者。 构建方法最终在建设者状态上做了大量工作。

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

如果我想确保onTopOf(base:Base)只被调用一次,然后只with(ingredient:Ingredient)build():Pizza可以调用build():Pizza ,a-la是一个定向的生成器,我将如何去接近这个?


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

以下使用字符串作为简洁/速度的值...

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)

这里有三个主要的选择。

  • 使用与Java,类和全部相同的模式。

  • 使用命名参数和默认参数以及复制方法。 案例类已经为您提供了这个,但这里有一个不是案例类的例子,只是为了让您更好地理解它。

    object Size {
        sealed abstract class Type
        object Large extends Type
    }
    
    object Base {
        sealed abstract class Type
        object Cheesy extends Type
    }
    
    object Ingredient {
        sealed abstract class Type
        object Ham extends Type
    }
    
    class Pizza(size: Size.Type, 
                base: Base.Type, 
                ingredients: List[Ingredient.Type])
    
    class PizzaBuilder(size: Size.Type, 
                       base: Base.Type = null, 
                       ingredients: List[Ingredient.Type] = Nil) {
    
        // A generic copy method
        def copy(size: Size.Type = this.size,
                 base: Base.Type = this.base,
                 ingredients: List[Ingredient.Type] = this.ingredients) = 
            new PizzaBuilder(size, base, ingredients)
    
    
        // An onTopOf method based on copy
        def onTopOf(base: Base.Type) = copy(base = base)
    
    
        // A with method based on copy, with `` because with is a keyword in Scala
        def `with`(ingredient: Ingredient.Type) = copy(ingredients = ingredient :: ingredients)
    
    
        // A build method to create the Pizza
        def build() = {
            if (size == null || base == null || ingredients == Nil) error("Missing stuff")
            else new Pizza(size, base, ingredients)
        }
    }
    
    // Possible ways of using it:
    new PizzaBuilder(Size.Large).onTopOf(Base.Cheesy).`with`(Ingredient.Ham).build();
    // or
    new PizzaBuilder(Size.Large).copy(base = Base.Cheesy).copy(ingredients = List(Ingredient.Ham)).build()
    // or
    new PizzaBuilder(size = Size.Large, 
                     base = Base.Cheesy, 
                     ingredients = Ingredient.Ham :: Nil).build()
    // or even forgo the Builder altogether and just 
    // use named and default parameters on Pizza itself
    
  • 使用类型安全的生成器模式。 我所知道的最好的介绍是这个博客,其中还包含许多关于这个主题的其他文章的参考。

    基本上,类型安全构建器模式在编译时保证提供了所有必需的组件。 人们甚至可以保证相互排斥选择或礼貌。 成本是构建器代码的复杂性,但是...


  • 它是一样的确切模式。 斯卡拉允许突变和副作用。 也就是说,如果你想更纯粹一点,那么每个方法都会返回一个正在构建的对象的新实例,并且元素会被更改。 你甚至可以把这些函数放在类的对象中,这样你的代码中就可以有更高层次的分离。

    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)
    

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

    链接地址: http://www.djcxy.com/p/82687.html

    上一篇: What is the Scala equivalent to a Java builder pattern?

    下一篇: Polymorphic updates in an immutable class hierarchy