This is an excerpt from the Scala Cookbook (partially modified for the internet). This is Recipe 6.9, “How to implement the Factory Method in Scala with ‘apply.’”
Problem
To let subclasses declare which type of object should be created, and to keep the object creation point in one location, you want to implement the factory method in Scala.
Solution
One approach to this problem is to take advantage of how a Scala companion object’s apply
method works. Rather than creating a “get” method for your factory, you can place the factory’s decision-making algorithm in the apply
method.
For instance, suppose you want to create an Animal
factory that returns instances of Cat
and Dog
classes, based on what you ask for. By writing an apply
method in the companion object of an Animal
class, users of your factory can create new Cat
and Dog
instances like this:
val cat = Animal("cat") // creates a Cat val dog = Animal("dog") // creates a Dog
To implement this behavior, create a parent Animal
trait:
trait Animal { def speak }
In the same file, create (a) a companion object, (b) the classes that extend the base trait, and (c) a suitable apply
method:
object Animal { private class Dog extends Animal { override def speak { println("woof") } } private class Cat extends Animal { override def speak { println("meow") } } // the factory method def apply(s: String): Animal = { if (s == "dog") new Dog else new Cat } }
This lets you run the desired code:
val cat = Animal("cat") // returns a Cat val dog = Animal("dog") // returns a Dog
You can test this by pasting the Animal
trait and object into the REPL, and then issuing these statements:
scala> val cat = Animal("cat") cat: Animal = Animal$Cat@486f8860 scala> cat.speak meow scala> val dog = Animal("dog") dog: Animal = Animal$Dog@412798c1 scala> dog.speak woof
As you can see, this approach works as desired.
Discussion
You have a variety of ways to implement this solution, so experiment with different approaches, in particular how you want to make the Cat
and Dog
classes accessible. The idea of the factory method is to make sure that concrete instances can only be created through the factory; therefore, the class constructors should be hidden from all other classes. The code here shows one possible solution to this problem.
If you don’t like using the apply
method as the factory interface, you can create the usual “get” method in the companion object, as shown in the getAnimal
method here:
// an alternative factory method (use one or the other) def getAnimal(s: String): Animal = { if (s == "dog") return new Dog else return new Cat }
Using this method instead of the apply
method, you now create new Animal
instances like this:
val cat = Animal.getAnimal("cat") // returns a Cat val dog = Animal.getAnimal("dog") // returns a Dog
Either approach is fine; consider this recipe as a springboard for your own solution.
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |
See Also
- Recipe 6.8 for more examples of implementing the Scala
apply
method. - My Java Factory Pattern tutorial