How to implement the Factory Method in Scala with ‘apply’

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.

See Also