Tuesday, May 2, 2023

Static Factory Method in Kotlin comparative analysis with Java

 Static Factory Method 

The Static Factory Method was popularized by Joshua Bloch in his book Effective Java. To understand it better, let's look at the examples from Java standard library itself, the valueOf() methods: 

Long l1 = new Long("1");

Long l2 = Long.valueOf("1"); 

Both the constructor and the valueOf() method receive String as input and produce Long as output. So, why is the Static Factory Method sometimes better than a constructor?

Advantages of the Static Factory Method Here are some of the advantages of a Static Factory Method over constructors: It provides a better name for the constructor, what it expects, and, sometimes, what it produces.

We usually don't expect exceptions from a constructor. Exceptions from a regular method, on the other hand, are totally valid. Speaking of expectations, we expect the constructor to be fast.  But those are more psychological advantages. There are also some technological advantages to this approach.

Caching The Static Factory Method may provide caching, as Long actually does. Instead of always returning a new instance for any value, valueOf() checks in-cache whether this value was already parsed. If it is, it returns a cached instance. Repeatedly calling the Static Factory Method with the same values may produce less garbage for collection than using constructors all the time.

Subclassing When calling the constructor, we always instantiate the class we specify. On the other hand, calling a Static Factory Method may produce either instance of the class, or one of its subclasses. We'll come to this after discussing the implementation of this design pattern in Kotlin.

Static Factory Method in Kotlin I've already discussed the object keyword earlier in the Singleton section. Now we'll see another use of it is a companion object. In Java, Static Factory Methods are declared static. But in Kotlin, there's no such keyword. Instead, methods that

don't belong to an instance of a class can be declared inside a companion object: 

class NumberMaster {

    companion object {

        fun valueOf(hopefullyNumber: String) : Long {

            return hopefullyNumber.toLong()

        }

    }

Companion objects may have a name: companion object Parser, for example. But this is only for clarity of what the goal of this object is. Calling a companion object doesn't require instantiating a class:

println(NumberMaster.valueOf("123")) // Prints 123 

Moreover, calling it on an instance of a class simply won't work, unlike Java:

 println(NumberMaster().valueOf("123")) // Won't compile The class may have only one companion object.

Companion object In Java, Static Factory Methods are declared like this: private static class 

MyClass { 

 // Don't want anybody to use it but me 

  private MyClass() { 

  } 

 // This will replace the public constructor 

  public static MyClass create() { 

    return new MyClass();

}  

They are called like this: MyClass myClass = MyClass.create();  

But in Kotlin, there's no such keyword as Static. Instead, methods that don't belong to an instance of a class can be declared inside a companion object. We discussed the object keyword earlier, in the section Singletons. Now, we'll look at another use of this important keyword using the following example:   

 class NumberMaster { 

       companion object { 

           fun valueOf(hopefullyNumber:String) : Long { 

               return hopefullyNumber.toLong() 

           }  

       } 

   }  

As you can see, inside our class, we have declared an object that is prefixed by the keyword companion. This object has its own set of functions. What's the benefit of this? You may wonder. Just like a Java Static method, calling a companion object doesn't require the instantiation of a class:

println(NumberMaster.valueOf("123")) // Prints 123  

Moreover, calling it on an instance of a class simply won't work, which is not the case with Java: println(NumberMaster().valueOf("123")) // Won't compile  

A companion object may have a name-Parser, for example. But this is only for clarity of what the goal of this object is.

The class may have only one companion object.

By using a companion object, we can achieve exactly the same behavior that we see in Java:

 private class MyClass private constructor() { 

    companion object { 

        fun create(): MyClass { 

            return MyClass() 

        } 

    } 

}  

We can now instantiate our object, as shown in the following code: // This won't compile 

//val instance = MyClass()

// But this works as it should 

val instance = MyClass.create()  Kotlin proves itself a very practical language. Every keyword in it has a down-to-earth meaning.

Code Example :

class StaticFactoryMethod {
companion object Parser {
fun valueOf(hopefullyNumber: String): Long {
return hopefullyNumber.toLong()
}
}
}

 fun main(args: Array<String>) {

    // Singleton test
    for (i in 1..10){
SingletonAnalysisWithJava.increment()
}
// Factory Method test
val animalTypes = listOf("dog" to "bulldog",
"dog" to "beagle",
"cat" to "persian",
"cat" to "russian blue",
"cat" to "siamese")

val factory = FactoryMethod()
for ((type, breed) in animalTypes) {
val c = factory.createAnimal(type, breed)
println(c)
}
// Static Factory Method
val n = StaticFactoryMethod()
println(StaticFactoryMethod.valueOf("123"))
}
Output : 123

1 comment:

Anonymous said...

Very well explained and easy to understand.