score:59
Another alternative to the Builder pattern in Scala 2.8 is to use immutable case classes with default arguments and named parameters. Its a little different but the effect is smart defaults, all values specified and things only specified once with syntax checking...
The following uses Strings for the values for brevity/speed...
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)
You can then also use existing immutable instances as kinda builders too...
scala> val lp2 = p3.copy(base = "Large")
lp2: Pizza = Pizza(List(Ham, Pineapple),Large,Edam)
score:0
using Scala partial applies are feasible if you are building a smallish object that you don't need to pass over method signatures. If any of those assumptions don't apply, I recommend using a mutable builder to build an immutable object. With this being scala you could implement the builder pattern with a case class for the object to build with a companion as the builder.
Given that the end result is a constructed immutable object I don't see that it defeats any of the Scala principles.
score:11
It's the same exact pattern. Scala allows for mutation and side effects. That said, if you'd like to be more of a purest, have each method return a new instance of the object that you're constructing with the element(s) changed. You could even put the functions within the Object of a class so that there's a higher level of separation within your code.
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)
}
so that your code might look like
val myPizza = new Pizza(Large) onTopOf(MarinaraSauce) onTopOf(Cheese) withTopping(Ham) withTopping(Pineapple)
(Note: I've probably screwed up some syntax here.)
score:13
Case classes solve the problem as shown in previous answers, but the resulting api is difficult to use from java when You have scala collections in your objects. To provide a fluent api to java users try this:
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
}
Then in java code the api is really easy to use
SEEConfigurationGrammar builder = SEEConfigurationBuilder.empty();
SEEConfiguration configuration = builder
.withParameter(new Parameter("name","value"))
.withParameter("directGivenName","Value")
.withPlugin(new PlugIn("pluginid"))
.build();
score:33
You have three main alternatives here.
Use the same pattern as in Java, classes and all.
Use named and default arguments and a copy method. Case classes already provide this for you, but here's an example that is not a case class, just so you can understand it better.
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
Use a type safe builder pattern. The best introduction I know of is this blog, which also contains references to many other articles on the subject.
Basically, a type safe builder pattern guarantees at compile time that all required components are provided. One can even guarantee mutual exclusion of options or arity. The cost is the complexity of the builder code, but...
Source: stackoverflow.com
Related Query
- What is the Scala equivalent to a Java builder pattern?
- What is the Java equivalent of a Scala object?
- What is the advantage of using scala pattern matching instead of java switch case?
- What is the Java equivalent of this Scala code?
- Scala 2.12: What is the equivalent of Java 8 method reference for universally quantified SAM trait?
- What is the equivalent of scala companion objects in Java Akka?
- What is the equivalent log4j statement in scala for the below java code
- What are the differences and similarties between Scala traits vs. Java 8 interfaces?
- What is the Scala equivalent of Java's ClassName.class?
- What is/are the Scala way(s) to implement this Java "byte[] to Hex" class
- What are the differences between a Scala Future and a Java Future
- What should a Scala developer know about Java and/or the JVM?
- Scala perf: Why is this Scala app 30x slower than the equivalent Java app?
- What is the Scala equivalent of F#'s async workflows?
- What is the performance impact of using the type class pattern in Scala
- What is the Scala equivalent of Clojure's Atom?
- What is the difference between scala @Serializable and Java Serializable?
- What is the Scala equivalent to Clojure's threading macros?
- Scala or Java equivalent of Ruby factory_girl or Python factory_boy (convenient factory pattern for unit testing)
- What is the IO Haskell Monad equivalent in Scala standard API?
- What is the best way to extend a Java Exception in Scala properly?
- What is the Scala equivalent of C++ typeid?
- What are the benefits of using the scala akka toolkit vs java akka toolkit version?
- What is the Tensorflow Java Api `toGraphDef` equivalent in Python?
- Scala replacement for a Java enum pattern I use all the time
- What is the most succinct Scala way to invoke a Java 8 functional interface?
- What is the equivalent Scala for the following Python statement?
- What is the difference between this two following cases of pattern matching in scala
- What is the Scala equivalent of the `this` operator in Java?
- What scala or java library can be used to crawl +10M pages daily from 1000 domains in the most efficient way
More Query from same tag
- Scala: How to get context bound List[T] conversion working here?
- I am not able to reach my sessions route, issue with my routing DSL code in my akka-http app
- Is it possible to serialize non case classes in Scala?
- Map with different types to String
- Why does Option require explicit toList inside for loops?
- Spark write to S3 bucket giving java.lang.NoClassDefFoundError
- Scala errors in Eclipse 3.5 using Scala 2.8.0b, "Syntax error on token String"
- Scala XML - passing down values using the .map method in XML
- Jsoup select by attribute containing single quotes (Scala)
- Scala string pattern matching by multiple possible groups
- Scala 3 - Instantiate class from List[String]
- Monte Carlo calculation of Pi in Scala
- Twitter Future timeout doesn't apply to the whole flatMap chain
- create a Spark DataFrame from a nested array of struct element?
- apply multiple filter conditions and produce only one element from a list
- Task#apply versus Task#delay
- Are scala case patterns first class?
- Can Scala case classes match in both an inherited and non-inherited function?
- Why should we avoid public methods? Benefits of encapsulation
- Variable has been Initialized in Scala class, but what it print is null?
- Prepend to String array
- What would be the best way to define a gatling a user flow using ChainBuilder?
- How can I update TableView in ScalaFX?
- Mess with async function with two threads in Play app
- Play2 add new field to JsObject
- Scala "<-" for comprehension
- How to get Java's int.class in Scala?
- Ruby's inject method like for Scala collections: any idea?
- Scala Style Guide: Why Mimic a function?
- Is the reason we can use val defining functions in Scala?