可重置的单Rx模式

时间:2018-01-07 22:04:08

标签: rx-java2 rx-kotlin2

我有以下设计我想创建,但我不确定哪种Rx模式匹配它。目标或多或少是单一的,但有条件检查。

  • 有一个Observable<String>,可能有多个观察员。
  • 如果首先发出请求,observable将执行一些接收字符串的网络请求,然后发出回调(很像可完成/单个)
  • 使用相同密钥的任何后续呼叫将立即返回相同的结果
  • 但是,如果5分钟过去并且进行了相同的调用,我们将重新获取可能已过期的数据,然后将其发送给任何侦听器。此结果将再保存5分钟,并且循环重复。
  • 所有数据都是根据发送的密钥存储的,就像一个flyweight模式。到期时间取决于特定密钥的最后请求时间。

我最初的想法是使用并发的哈希映射创建自己的类。但是,这意味着我必须自己处理很多线程机制。我觉得RxJava将是一个很好的解决方案,但我不确定这些模式是否存在。有没有人有想法?

我知道Single<T>的目的只是为了检索单个回复,所以我的用语可能不正确。

以下是我的尝试,我将在更新时进行更新

/**
 * Created by Allan Wang on 07/01/18.
 *
 * Reactive flyweight to help deal with prolonged executions
 * Each call will output a [Single], which may be new if none exist or the old one is invalidated,
 * or reused if an old one is still valid
 *
 * Types:
 * T    input       argument for caller
 * C    condition   condition to check against for validity
 * R    response    response within reactive output
 */
abstract class RxFlyweight<in T : Any, C : Any, R : Any> {

    /**
     * Given an input emit the desired response
     * This will be executed in a separate thread
     */
    protected abstract fun call(input: T): R

    /**
     * Given an input and condition, check if
     * we may used cache data or if we need to make a new request
     * Return [true] to use cache, [false] otherwise
     */
    protected abstract fun validate(input: T, cond: C): Boolean

    /**
     * Given an input, create a new condition to be used
     * for future requests
     */
    protected abstract fun cache(input: T): C

    private val conditionals = mutableMapOf<T, C>()
    private val sources = mutableMapOf<T, Single<R>>()

    private val lock = Any()

    /**
     * Entry point to give an input a receive a [Single]
     * Note that the observer is not bound to any particular thread,
     * as it is dependent on [createNewSource]
     */
    operator fun invoke(input: T): Single<R> {
        synchronized(lock) {
            val source = sources[input]

            // update condition and retrieve old one
            val condition = conditionals.put(input, cache(input))

            // check to reuse observable
            if (source != null && condition != null && validate(input, condition))
                return source

            val newSource = createNewSource(input).cache()

            sources.put(input, newSource)
            return newSource
        }
    }

    /**
     * Open source creator
     * Result will then be created with [Single.cache]
     * If you don't have a need for cache,
     * you likely won't have a need for flyweights
     */
    open protected fun createNewSource(input: T): Single<R> =
            Single.fromCallable { call(input) }
                    .timeout(20, TimeUnit.SECONDS)
                    .subscribeOn(Schedulers.io())

    fun reset() {
        synchronized(lock) {
            sources.clear()
            conditionals.clear()
        }
    }

}

0 个答案:

没有答案