How to implement a template design template in Kotlin?

Consider the problem:

We have a Base class with an abstract method. Now we would like to ensure that every redefinition of this method performs some argument checking or some other work. We want this argument to be identical in all overrides. One solution would be to wrap this behavior in a non-abstract method that calls abstract:

 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, so no subclass of Base can call it accidentally without checking its arguments. Unfortunately this is not possible:

Error: (9, 5) Kotlin: The modifier 'private' is incompatible with 'Abstract'

Kotlin protected better than Java protected , as it makes the function available only to subclasses, but the ideal case would nevertheless be private .

So, is there a proper way to implement this template? Also, out of curiosity, is the incompatibility of private and abstract deliberate choice of language design?

+5
source share
2 answers

It does not make sense for the function to be overridden, but not called from this class. Overriding this function, you own its implementation and, therefore, you can call it.

You can accomplish what you want by separating execution logic from derived classes, which can be done in several ways:

  • You can use lambda and pass this to Base constructor
  • You can create an implementation of an interface that processes execution logic.

By passing them to the Base class in your constructor, you pass your property to this class.

+2
source

You can force them to pass an 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 the derived class would like to call execute, it needs to pass an object that checks the value when creating the instance

+1
source

Source: https://habr.com/ru/post/1272591/


All Articles