Showing posts with label factory-method. Show all posts
Showing posts with label factory-method. Show all posts
Monday, November 2, 2009
Multiple Constructors
In Scala there is a primary constructor:
First multiple constructors:
In Java if a constructor calls another constructor that call must be the first statement in the constructor. Scala is the same except that in Scala the primary constructor must be called. Notice that all constructors call this(param1,param2) at some point. In addition any method defined in the class HelloConstructor is not available until after the primary constructor is invoked. The following examples are not valid.
Factory companion objects can be used to work around these restrictions:
Since companion objects can access private members of the class the factory methods can be as powerful as a constructor without the restrictions.
One last idea that is useful when designing classes is Scala 2.8 default arguments:
class MyClass(constructorParam:Any)
. Unlike Java, that constructor must be called. The question that often arises is, "How can one define multiple constructors?" There is a simple way to do this, however often a factory companion object can be used to remove the need for multiple constructors. Factory Companion Objects are covered in a previous post but I will review the pattern here quickly.First multiple constructors:
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def this(onlyParam:Int) = this(onlyParam,onlyParam)
- | def this(p1:String, p2:String, p3:String) = this(p1.length, p2.length + p3.length)
- | def this(onlyParam:String) = this(onlyParam.length)
- | }
- defined class HelloConstructor
In Java if a constructor calls another constructor that call must be the first statement in the constructor. Scala is the same except that in Scala the primary constructor must be called. Notice that all constructors call this(param1,param2) at some point. In addition any method defined in the class HelloConstructor is not available until after the primary constructor is invoked. The following examples are not valid.
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def x = 1
- | def this() = this(x,3)
- | }
- <console>:6: error: not found: value x
- def this() = this(x,3)
- scala> class HelloConstructor(param1:Int, param2:Int) {
- | def this() = {
- | println("constructing") // the REPL won't even let me finish method definition
- <console>:3: error: 'this' expected but identifier found.
- println("constructing")
- ^
Factory companion objects can be used to work around these restrictions:
- scala> class HelloConstructor(param1:Int, param2:Int)
- defined class HelloConstructor
- scala> object HelloConstructor {
- | def apply() = {
- | println("constructing object")
- | new HelloConstructor(1,2)
- | }
- | }
- defined module HelloConstructor
- scala> HelloConstructor()
- constructing object
- res1: HelloConstructor = HelloConstructor@5b0010ec
Since companion objects can access private members of the class the factory methods can be as powerful as a constructor without the restrictions.
One last idea that is useful when designing classes is Scala 2.8 default arguments:
- scala> class HelloConstructor(param1: Int = 1, param2: Int = 2)
- defined class HelloConstructor
- scala> new HelloConstructor()
- res0: HelloConstructor = HelloConstructor@7cd47880
- scala> new HelloConstructor(1)
- res1: HelloConstructor = HelloConstructor@3834a1c8
- scala> new HelloConstructor(param1 = 1)
- res2: HelloConstructor = HelloConstructor@3b3e3940
- scala> new HelloConstructor(param2 = 1)
- res3: HelloConstructor = HelloConstructor@6dee2ea8
- scala> new HelloConstructor(3,4)
- res4: HelloConstructor = HelloConstructor@397b6074
- scala> new HelloConstructor(param1 = 3, param2=4)
- res5: HelloConstructor = HelloConstructor@20272fec
Labels:
beginner,
classes,
companion,
constructor,
factory-method,
Scala
Monday, September 14, 2009
Factory Methods and Companion Objects
One of the most common uses of a companion object (See Companion Objects for more) is as a factory for creating instances of the class. For example, there may be several overloaded apply methods which provide different ways of instantiating the object. This is often preferred to adding many constructors because Scala places restrictions on constructors that Java does not have.
One built in example of Factory methods in a companion object are when you create a case class.
Examples:
One built in example of Factory methods in a companion object are when you create a case class.
Examples:
- scala> case class Data(p1:Int, p2:String)
- defined class Data
- // This is using the generated (or synthetic) factory method.
- // call case classes have a factory method generated
- scala> Data(1,"one")
- res0: Data = Data(1,one)
- // This is the normal new syntax.
- // case-classes are normal object so they have one of these too
- scala> new Data(1,"one")
- res1: Data = Data(1,one)
- scala> class MyClass(val p1:Int, val p2:String)
- defined class MyClass
- // MyClass is a normal class so there is no
- // synthetic factory method
- scala> MyClass(1,"one")
:5: error: not found: value MyClass - MyClass(1,"one")
- ^
- // but of course you can create an instance normally
- scala> new MyClass(1,"one")
- res3: MyClass = MyClass@55444319
- // create the companion object with an apply factory method
- scala> object MyClass{
- | def apply(p1:Int, p2:String)=new MyClass(p1,p2)
- | }
- defined module MyClass
- // now you can create MyClass as if it was a case-class
- // It is not a case-class so you still don't have the other
- // synthetic methods like: equals, hash-code, toString, etc...
- scala> MyClass(1,"one")
- res4: MyClass = MyClass@2c5e5c15
Labels:
beginner,
case-classes,
classes,
companion,
factory-method,
object,
Scala
Wednesday, September 9, 2009
Companion Object
A companion object is an object with the same name as a class or trait and is defined in the same source file as the associated file or trait. A companion object differs from other objects as it has access rights to the class/trait that other objects do not. In particular it can access methods and fields that are private in the class/trait.
An analog to a companion object in Java is having a class with static methods. In Scala you would move the static methods to a Companion object.
One of the most common uses of a companion object is to define factory methods for class. An example is case-classes. When a case-class is declared a companion object is created for the case-class with a factory method that has the same signature as the primary constructor of the case class. That is why one can create a case-class like:
A second common use-case for companion objects is to create extractors for the class. I will mention extractors in a future topic. Basically extractors allow matching to work with arbitrary classes.
NOTE: Because the companion object and the class must be defined in the same source file you cannot create them in the interpreter. So copy the following example into a file and run it in script mode:
scala mysourcefile.scala
Example:
An analog to a companion object in Java is having a class with static methods. In Scala you would move the static methods to a Companion object.
One of the most common uses of a companion object is to define factory methods for class. An example is case-classes. When a case-class is declared a companion object is created for the case-class with a factory method that has the same signature as the primary constructor of the case class. That is why one can create a case-class like:
MyCaseClass(param1, param2)
. No new element is required for case-class instantiation.A second common use-case for companion objects is to create extractors for the class. I will mention extractors in a future topic. Basically extractors allow matching to work with arbitrary classes.
NOTE: Because the companion object and the class must be defined in the same source file you cannot create them in the interpreter. So copy the following example into a file and run it in script mode:
scala mysourcefile.scala
Example:
- class MyString(val jString:String) {
- private var extraData = ""
- override def toString = jString+extraData
- }
- object MyString {
- def apply(base:String, extras:String) = {
- val s = new MyString(base)
- s.extraData = extras
- s
- }
- def apply(base:String) = new MyString(base)
- }
- println(MyString("hello"," world"))
- println(MyString("hello"))
Labels:
beginner,
case-classes,
companion,
extractor,
factory-method,
object,
Scala
Subscribe to:
Posts (Atom)