Is there any way to intercept method from interface and cache result “WITHOUT” spring’s method cache ? Take a simple calculator for example :
interface ICalculate {
fun multiply(a: Int, b: Int): Int
}
It just multiplies a
and b
, and return the result . Suppose it is a heavy computation work . And there are two implementations :
class CalculatorDumb : ICalculate {
override fun multiply(a: Int, b: Int): Int {
var sum = 0
(1..a).forEach {
(1..b).forEach {
sum++
}
}
return sum
}
}
The dumb implementation just add one by one .
And there is a smart implementation :
class CalculatorSmart : ICalculate {
override fun multiply(a: Int, b: Int): Int {
return a * b
}
}
This smart implementation just returns a * b
.
OK , here is the point . I hope client can initialize no matter dumb or smart implementation , and can get result if the parameter is identical.
There is a Memoize pattern , described here : https://jorgecastillo.dev/kotlin-purity-and-function-memoization :
class Memoize<in T, out R>(val f: (T) -> R) : (T) -> R {
private val values = mutableMapOf<T, R>()
override fun invoke(x: T): R {
return values.getOrPut(x) { f(x) }
}
}
fun <T, R> ((T) -> R).memoize(): (T) -> R = Memoize(this)
I can use it in the implementation class , like this :
class CalculatorSmart : ICalculate {
data class CacheKey(val a: Int, val b: Int)
private val innerCalculate: (CacheKey) -> Int = { key: CacheKey ->
println("cache miss")
key.a * key.b
}.memoize()
override fun multiply(a: Int, b: Int): Int {
return innerCalculate(CacheKey(a, b))
}
}
But it seems it’s hard to apply it in the interface layer.
I wonder if there are any patterns to achieve :
- Each implementation class ( dumb or smart in this example) doesn’t need to implement its own cache .
- There are NO two public versions of method defined in interface ( for example : actual
multiply()
andcachedMultiply()
whilecachedMultiply
checks cache and redirect tomultiply
if necessary ) - Client only knows one method of the interface , No matter the client initialize smart or dumb class , the result of the same parameter will be cached and returned.
For example : such scenario is OK
val calSmart: ICalculate = CalculatorSmart()
println(calSmart.multiply(3, 7)) // cache miss
println(calSmart.multiply(3, 7)) // cache hit
val calDumb: ICalculate = CalculatorDumb()
println(calDumb.multiply(3, 7)) // cache miss
println(calDumb.multiply(3, 7)) // cache hit
It will work like Spring’s method cache . but I hope there will be a kotlin-idiomatic style , maybe more functional , just like the memoization pattern above . Is there any idea ?
Thanks.
Aucun commentaire:
Enregistrer un commentaire