Factory Method

The Factory method pattern is one of the creational software patterns, described in the book of the Gang-Of-Four. It deals with the problem of creating objects and the business logic to create the objects. The idea of the factory is to decouple the construction of objects from the objects themselves. There are different kind of factories and factory methods which solve different problems of the object creation.

  1. Static Factory Method
  2. “Normal” Factory Class
  3. “Advanced” Factory Class
  4. Abstract Factory Pattern

The Static Factory Method implements static functions to create object instead of overloading the constructor of a class. The “Normal” Factory Class uses a factory to decide which subtype shall be created. The “Advanced” Factory Class breaks the factory class in an abstract factory and specialized child classes. The Abstract Factory Pattern takes the last step and goes one step further. The last pattern is analyzed in a specific chapter.

Static Factory Method

Imagine a simple geometry program which can show circles. A circle is represented by a Circle class which is internally characterized by its center point and the radius. The center point will be of type Point, which is a class holding the cartesian values of a point.

The Point class

class Point(var x: Double, var y: Double)

The Circle class

class Circle (var center: Point, var radius: Double)

Usage of Circle class

var center = Point(5.0, 10.0)
    
var radius = 10.0
var circle1 = Circle(center, radius)

var diameter = 20.0
var circle2 = Circle(center, diameter / 2.0)
var circle3 = Circle(center, diameter)  // this will be a bug

The circle class expects as an input argument the center point and a double (which represents the radius). In real live however, a circle can be represented in different ways: e.g. with its diameter instead of the radius. This leads to a great ambiguious behavior, code duplication and potential for future bugs. First it is not clear from the interface if the input is a radius or a diameter (both are doubles). This leads to potential misusages of the circle class. Second, in case the user has different properties (e.g. 3 points on the circle), he must do the math himself. This again is error-prone and leads to duplicated code. The best would be to provide special methods which are in charge to create the circle objects from different properties.

To achieve this, we make the constructor of the Circle class private. So, nobody outside of this class can instantiate objects and therefore cannot make any mistakes.

Afterwards we provide specialize functions to construct circles (in this case the fromRadius and fromDiameter). These functions should not bound to any object. In Java or other OO languages one would use static methods. The problem is that in Kotlin there exist no static method. The work around is to use a companion object within the Circle class. The companion object will be a factory which provides factory methods to construct circles.

The Circle Class

class Circle private constructor(var center: Point, var radius: Double) {
    companion object Factory {
        fun fromRadius(center : Point, radius : Double) : Circle {
            return Circle(center, radius)
        }

        fun fromDiameter(center : Point, diameter : Double) : Circle {
            return Circle(center, diameter / 2.0)
        }
    }
}

Companion object in Kotlin

A “class” which uses the keyword object instead of class will lead to a singleton object. This means that at the whole runtime only one object is instantiated (in a thread safe manner). The companion modifier allows to access the member functions of the object directly via the containing class.

Usage of circle class

var center = Point(5.0, 10.0)

var radius = 10.0
var diameter = 20.0

var circle1 = Circle.fromRadius(center, radius)
var circle2 = Circle.fromDiameter(center, diameter)

Normal Factory Class

In general, a factory class in charge to create objects in the desired way. It encapsulates all the business logic to build the object. Let’s consider an example where we are having a Movie class which can be of different types (children, action and horror).

The Movie Class

enum class MovieType {
    CHILDREN, ACTION, HORROR
}

class Movie(var type: MovieType)

Then there are classes (such as the PriceCalculator) which are performing operations based on the type of the movie. The PriceCalculator for instance calculates different prices for the movie in function of the movie type.

The PriceCalculator Class

class PriceCalculator (private var movie: Movie){
    fun calculatePrice() : Int {
        return when(movie.type){
            MovieType.CHILDREN -> 1
            MovieType.ACTION -> 2
            MovieType.HORROR -> 3
        }
    }
}

Until that point this is ok. But what if there are many other classes which are behaving differently for different movie types. Then we are having many switch statements (in Kotlin When – Statements) which will lead to a lot of duplicated code and potential errors.

The RentingDaysCalculator Class

class RentingDaysCalculator (private var movie: Movie){
    fun maximumDays() : Int {
        return when(movie.type){
            MovieType.CHILDREN -> 5
            MovieType.ACTION -> 10
            MovieType.HORROR -> 15
        }
    }
}

From object-oriented software design point of view this class set up is not good. It is better to use polymorphism to decide which methods to use depending of the type. To solve this, we rearrange our classes and introduce a factory class.

First the Movie class will be redeclared as an interface with 2 abstract functions (price and maximumRentingDays). For each type of movie, a class will be created which will implement the IMovie interface.

The Movie Interface and derived classes

interface IMovie {
    fun price() : Int
    fun maximumRentingDays() : Int
}

class ChildrenMovie : IMovie {
    override fun price(): Int {
        return 1
    }

    override fun maximumRentingDays(): Int {
        return 5
    }
}

class ActionMovie : IMovie {
    override fun price(): Int {
        return 2
    }

    override fun maximumRentingDays(): Int {
        return 10
    }
}

class HorrorMovie : IMovie {
    override fun price(): Int {
        return 3
    }

    override fun maximumRentingDays(): Int {
        return 15
    }
}

In this way we are putting the behavior of the different movie types closer to the classes themselves. The advantage is that we are now having a code which follows single-responsibility-principle and open-closed-principle. This allows us to change or add behavior without breaking the existing system.

Second, we are introducing a movie factory class which is in charge to instantiate the objects depending of their types.

The MovieFactory (singleton) class

object MovieFactory {
    fun getMovie(type: MovieType) : IMovie{
        return when(type){
            MovieType.CHILDREN -> ChildrenMovie()
            MovieType.ACTION -> ActionMovie()
            MovieType.HORROR -> HorrorMovie()
        }
    }
}

Again, we are using the object modifier. This gives kind of a static method. At the end we must modify the PriceCalculator and RentingDaysCalculator classes.

The modified PriceCalculator Class

class PriceCalculator (private var movie: IMovie){
    fun calculatePrice() : Int {
        return movie.price()
    }
}

The modified RentingDaysCalculator Class

class RentingDaysCalculator (private var movie: IMovie){
    fun maximumDays() : Int {
        return movie.maximumRentingDays()
    }
}

They are now not in charge anymore to calculate the price or the days, but they forward it to the specific movie class. This setup is much better than before but has as well some draw backs. On the one hand, one can add new movie types, without changing the PriceCalculator and the RentingDaysCalculator. One must only create a new class which implements the IMovie interface and adapt the Factory class. Thus, this follows the open-closed principle. Additionally, the public interface of PriceCalculator and RentingDaysCalculator are not changed, which is again a SOLID principle. On the other hand, a change in the IMovie interface would require heavy refactoring. The class designer must think beforehand which functions are needed for the IMovie interface.

Advanced Factory Class

In the “advanced” factory method we are going to define a specific interface for a factory. Classes which implement the interface are responsible to instantiate the correct object (and the business logic which is involved).

UML Diagram of Factory method

Factory Method UML Diagram

Our example scenario

Imagine a game where different kind of enemies exist (e.g. soldiers and birds). With a normal factory class, we would create the classes the following ways.

Enum Types and different enemy types

enum class EnemyTypes{
    GROUND, AIR
}
interface IEnemy{
    fun attack()
    fun block()
    fun escape()
}

class Bird : IEnemy{
    override fun attack() {}
    override fun block() {}
    override fun escape() {}
}

class Soldier : IEnemy {
    override fun attack() {}
    override fun block() {}
    override fun escape() {}
}

Normal (singleton) factory class.

object LevelFactory{
    fun getEnemy(type: EnemyTypes) : IEnemy {
        return when(type){
            EnemyTypes.GROUND -> Soldier()
            EnemyTypes.AIR -> Bird()
        }            
    }
}

This is the same setup as in the previous example. This class becomes unhandy when more functionality is added to the LevelFactory class which is dependend on the type of enemy. This is illustrated in the changed class.

object LevelFactory{
    fun getEnemy(type: EnemyTypes) : IEnemy {
        
        var enemy = when(type){
            EnemyTypes.GROUND -> Soldier()
            EnemyTypes.AIR -> Bird()
        }
        
        return setProperties(type, enemy)
    }
    
    private fun setProperties(type: EnemyTypes, enemy : IEnemy) : IEnemy {
        var stat = when (type){
            EnemyTypes.GROUND -> 1
            EnemyTypes.AIR -> 2
        }
        // do something with the stats
        return enemy
    }
}

One can see that again the switch statement is duplicated. So, we are running into the same problems as before. To solve this problem we split the Factory class in different classes. Each class is responsible to provide the specific business rules.

LevelFactory interface with default implementation

interface ILevelFactory{
    fun getEnemy() : IEnemy {
        var enemy = createEnemy()
        return setProperties(enemy)        
    }
    
    fun createEnemy() : IEnemy
    fun setProperties(enemy: IEnemy) : IEnemy
}

Concrete factories

class FlightLevel : ILevelFactory {
    override fun setProperties(enemy: IEnemy): IEnemy {
        // do something specific to air enemies
        return enemy
    }

    override fun createEnemy(): IEnemy {
        return Bird()
    }
}

class GroundLevel : ILevelFactory {
    override fun createEnemy(): IEnemy {
        return Soldier()
    }

    override fun setProperties(enemy: IEnemy): IEnemy {
        // do something specific to ground enemies
        return enemy
    }
}

Abstract Factory Pattern

The abstract factory pattern goes even a step further. It groups objects which belong together in different factories. We are going in detail in this design pattern in this page:

Conclusion

We had a look in different ways to create objects with factory methods or classes. The simplest case is create specific functions within the class which will be instantiated.

Afterwards a specific factory class was presented. This class collects the information of how specific sub types of classes will be created.

Later we have shown how to divide the factory in subclasses to bundle even more the construction process. The last implementation is already close to the Abstract Factory Pattern.