Implement null object pattern

319 Views Asked by At

I found this question which implements a null object pattern in Kotlin in a certain way. I usually do it a little different in Java:

class MyClass {
    static final MyClass INVALID = new MyClass();

    public MyClass() {
       // empty
    }
}

in this way, I can always use MyClass.INVALID as the null object.

How can I achieve this style in Kotlin?

I fiddled with something like this:

data class MyClass(val id: Int) {
    object INVALID: MyClass {
    }
}

but that doesn't even compile.

2

There are 2 best solutions below

1
Laksitha Ranasingha On BEST ANSWER

One way you could achieve this is by using a companion object. Because the members of the companion object can be called by using simply the class name as the qualifier. You could do;

data class MyClass(val id: Int) {
    companion object {
        @JvmStatic
        val nullInstance = MyClass(0)  //0 or any intended value
    }
}

//invocation
 val a = MyClass.nullInstance
 val b = MyClass.nullInstance
 print(a == b) //prints true because these are equavalent to Java's static instances.

Here I have annotated that nullInstance as @JvmStatic to have it generated as a real static member.

https://kotlinlang.org/docs/reference/object-declarations.html

0
zsmb13 On

You're on the right track, the problem you'll have that way is that you can't inherit from a data class.

You could either restructure your code to use an interface, something like this:

interface MyClass {
    val id: Int

    object INVALID : MyClass {
        override val id: Int = -1
    }
}

data class RealMyClass(override val id: Int) : MyClass

Or have an open class that can be inherited from as the base, which gives you a bit more concise code, as you can reuse the properties declared in the base class in the case of the null object - you do still have to override it in your data class, since all data class constructor parameters need to be properties.

open class MyClass(open val id: Int) {
    object INVALID : MyClass(-1)
}

data class RealMyClass(override val id: Int) : MyClass(id)