While working on a new Scala application recently, the alarms started going off in my head, saying "You need to use the Factory Pattern here." That's when things got interesting.
Just exactly how do you implement the Factory Pattern in Scala?
Here's a simple, quick example.
1) The interface
Sparing you all the experiments I went through, let's assume you want a factory that produces animals like this:
val dog = AnimalFactory.getAnimal("dog") val cat = AnimalFactory.getAnimal("cat") dog.speak cat.speak
Given that goal, let's start with a simple Animal interface, which is a trait in Scala:
trait Animal { def speak }
2a) The factory and concrete classes
Next, I wanted to make sure that only my factory could produce concrete instances of Dogs and Cats,. For a simple example, this looks like the best way to implement this in Scala:
object Animal { private class Dog extends Animal { override def speak { println("woof") } } private class Cat extends Animal { override def speak { println("meow") } } // our 'factory' method def apply(s: String):Animal = { if (s == "dog") return new Dog else return new Cat } }
There are other ways to deal with keeping your concrete instances private when your program gets larger, but this is a start (and makes for a simple example).
As mentioned, I chose this approach because I don't want other developers to be able to create Dog and Cat instances directly. With this design, attempts like these will fail:
// these attempts won't work //val d = new Dog //val a = new Animal.Cat
If you want a Dog or Cat, you'll have to get it from the factory.
2b) Differences from Java
A significant difference from Java (and possibly other languages) is using the apply method as the method consumers should call to get a concrete instance. However, if you know your Scala, you know that this lets you create a new Dog like this:
val d = Animal("dog")
I think that's pretty darned convenient. As an alternative, I could define a factory method like this:
def getAnimal(s: String):Animal = { if (s == "dog") return new Dog else return new Cat }
and then get concrete instances like this:
val dog = Animal.getAnimal("dog") val cat = Animal.getAnimal("cat")
There's nothing wrong with that, but I prefer the apply approach.
Summary: A complete, simple Scala Factory Pattern example
Putting it all together into one simple Scala Factory Pattern example, here's some source code you can copy, paste, and experiment with:
/** * A Scala Factory Pattern example by Alvin Alexander, * http://devdaily.com */ package factory trait Animal { def speak } object Animal { private class Dog extends Animal { override def speak { println("woof") } } private class Cat extends Animal { override def speak { println("meow") } } // my preferred factory method def apply(s: String):Animal = { if (s == "dog") return new Dog else return new Cat } // an alternative factory method (use one or the other) def getAnimal(s: String):Animal = { if (s == "dog") return new Dog else return new Cat } } object Driver extends App { val dog = Animal("dog") dog.speak val cat = Animal("cat") cat.speak Animal.getAnimal("dog").speak Animal.getAnimal("cat").speak }
I'll try to put a more complicated example out here in the future, but for now, if you ever need to implement the Factory Method in Scala, I hope this example is helpful.