Companion Factory Methods in Kotlin

In Java, static factory methods are useful to instantiate a Type when we don’t want to expose what implementation is produced. If we find a better way, or the business requirements change, we can change it internally without affecting the client of our Type.

It’s specially useful when our Type doesn’t take too many arguments. If we have more than 2 or 3, it may be more beneficial to use a Builder Object instead.

For example, let’s say that we have a lighting system that has different lifecycles depending on the day of the week:

In order to create the day of the week we can create a static factory method that takes an Epoc timestamp as a parameter:

In Kotlin we can create a “static” function to a Type by adding it to its companion object:

Companion objects are tied to a Type and not to a particular instance. They are the equivalent to static methods in Java. And they are called in the same way:

However, in Kotlin, we have more options. On my previous post, Extending Resources, we saw how we can override operators in Kotlin to have more semantic function calls.

We applied the invoke() operator to an instance. However, if we use the same pattern on a companion object, we can get more interesting results:

Now, our client will be able to use this API like if they were calling a constructor of DayOfTheWeek:

This makes it simple to provide an API which is easier to use.

One last thing

Builder objects were mentioned earlier. If we need to do so, Kotlin makes our life a lot easier. There are two features that help us with this pattern: named arguments and default arguments.

One of the issues the Builder Pattern solves is that when having a large number of parameters, it’s hard to follow what’s what (specially if their type is the same). Look at the constructor of Rect:

It’s not very clear what each value represents. Some IDEs like IntelliJ and Android Studio help by adding small labels to each of the parameters. However, that luxury is not always available (GitHub for instance).

Unfortunately, we can’t use named arguments on non-Kotlin classes. If you are fortunate of working with a Kotlin codebase, you can create an object like this:

Much easier to read and quite similar to a builder object.

Another useful feature of Builders is that you can leave some parameters as optional. Here is where default parameters become rather useful:

Here we are making right and bottom take the value of left and top. So if we only provide two values we have a point:

It’s possible to also have hardcoded values:

This pattern can help you create interesting Objects without so much boiler plate code. The one aspect that can cause some trouble is that the client can decide to ignore the named methods and use your function/constructor in the old way. Some may argue that it gives them more freedom though.

Could be worse though, they could be using mid-function returns.

Written by

Software Artisan

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store