Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement the template method design pattern in Kotlin?

Consider the problem:

We have a Base class with an abstract method. Now, we would like to enforce that every override of this method will perform some argument checking or some other drudgery. We want this argument checking to be identical across all overrides. One solution would be to wrap this behavior in a non-abstract method which calls an abstract one:

abstract class Base
{
    fun computeSomething(argument: Int): Int
    {
        require(argument > 0) // Some intricate checking
        return execute(argument)
    }

    // Pure functionality, assuming correct arguments
    // Ideally, this would be private. 
    protected abstract fun execute(validArgument: Int): Int
}

class Derived1: Base()
{
    override fun execute(validArgument: Int): Int =
        validArgument * validArgument
}

class Derived2: Base()
{
    override fun execute(validArgument: Int): Int =
        validArgument * validArgument * validArgument
}


fun main(args: Array<String>)
{
    val d = Derived1()
    println(d.computeSomething(23))
}

I would like to have Base::execute private, such that no subclass of Base can call it by accident without checking its arguments. Unfortunately, this is not possible:

Error:(9, 5) Kotlin: Modifier 'private' is incompatible with 'abstract'

Kotlin's protected is better than Java's protected, since it makes the function accessible only to subclasses but still, the ideal case would be private.

So is there some right way to implement this pattern? Also, just out of curiosity, is the incompatibility of private and abstract a deliberate choice of language design?

like image 897
Martin Drozdik Avatar asked Oct 13 '17 11:10

Martin Drozdik


2 Answers

It doesn't make sense for a function to be overridden, but not callable from that class. By overriding that function, you own its implementation, and therefore can call it.

You can accomplish what you want by detaching the execution logic from the derived classes, which can be done in a few ways:

  • You could make use of a lambda, and pass that to the constructor of the Base
  • You could create an interface implementation that handles the execution logic

By passing these to the Base class in its constructor, you are transferring their ownership to that class.

like image 147
Gegy Avatar answered Oct 07 '22 03:10

Gegy


You can make them to pass object that will check the value if they would like to call this method. example

abstract class Base
{
    fun computeSomething(argument: Int): Int
    {
        return execute(ValueCheck(argument))
    }

    protected abstract fun execute(validArgument: ValueCheck)

    protected class ValueCheck(a: Int)
    {
        private val value = checkValue(a)

        private fun checkValue(argument: Int): Int
        {
            require(argument > 0)
            return argument
        }

        fun get() = value
    }
}

and when derived class would like to call execute, it have to pass object that is checking value when creating instance

like image 25
V-master Avatar answered Oct 07 '22 02:10

V-master