首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Kotlin接口可以缓存值吗?

Kotlin接口可以缓存值吗?
EN

Stack Overflow用户
提问于 2017-04-18 15:50:43
回答 3查看 1.4K关注 0票数 1

我非常喜欢为Kotlin中的接口使用默认实现,特别是对于可观察的常见模式。这是我的界面

代码语言:javascript
复制
interface Observable<T>{

    // How do I cache this?
    val observers: MutableList<Observer<T>>
        get() = LinkedList<>()

    fun addObserver(o:Observer<T>){
        observers.add(o)
    }

    fun removeObserver(o:Observer<T>){
        observers.remove(o)
    }

    fun notifyObservers(u:T){
        for (o in observers){
            o.update(u)
        }
    }

}

接口引用了一个observers列表,但是get()调用每次都返回一个新的LinkedList()。如何缓存observers的值,使其只创建一次?我尝试过使用科特林-懒惰,但要么无法正确地使用语法,要么它不适用于接口。我的IDE抱怨“接口中不允许委托属性”。

更新

根据Yoav的回答,我改变了我的界面

代码语言:javascript
复制
interface Observable<T>{
    val observers: MutableList<Observer<T>>
}

然后在实现类中,

代码语言:javascript
复制
class MyObservable : Observable<String>

   private val _observers = LinkedList<Observer<String>>()

   override val observers: MutableList<Observer<String>>
       get() = _observers

有什么建议可以让这件事更简洁吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-04-18 16:18:10

根据Kotlin医生的说法:

Kotlin中的接口非常类似于Java 8,它们可以包含抽象方法的声明以及方法实现。与抽象类不同的是,接口不能存储状态。

接口不能保存任何状态,因为它们是完全抽象的。也许您应该使用abstract class来缓存这些值?

有关接口无状态的原因的更多信息,请参见问题。

接口是一个契约,指定它的实现者承诺能够做什么。它不需要指定状态,因为state是一个实现细节,只用于约束实现者如何履行该契约。如果要指定状态,则可能需要重新考虑接口的使用,转而查看抽象基类。

票数 4
EN

Stack Overflow用户

发布于 2021-09-04 16:31:01

虽然不能在接口上直接创建有状态变量,但是可以通过定义包含缓存的配套对象并在this上进行动态查找来实现相同的结果。使用您的例子:

代码语言:javascript
复制
interface Observable<T>{
  // How do I cache this?
  val observers: MutableList<Observer<T>>
    get() = cache.computeIfAbsent(this) { mutableListOf<Observer<T>>() } as MutableList<Observer<T>>

  fun addObserver(o:Observer<T>){
    observers.add(o)
  }

  fun removeObserver(o:Observer<T>){
    observers.remove(o)
  }

  fun notifyObservers(u:T){
    for (o in observers){
      o.update(u)
    }
  }

  companion object {
    val cache = WeakHashMap<Observable<*>, MutableList<*>>()
  }
}

如果您想要一个更有效的缓存,可以使用像咖啡因这样的库。

票数 0
EN

Stack Overflow用户

发布于 2022-03-26 23:04:09

再想一想,我发现了一个很好的模式。首先,我尝试了直接的方法:

代码语言:javascript
复制
interface A {
  val prop = compute() // Nope: Property initializers are not allowed in interfaces
  /*...*/
}

正如您所提到的,可以使用自定义访问器完成此操作,但每次都必须重新计算:

代码语言:javascript
复制
interface A {
  val prop get() = compute() // OK, but recomputed each time someProperty is read
  /*...*/
}

然后我想,也许我们可以用委托属性来代替?但这也是不允许的:

代码语言:javascript
复制
interface A {
  val prop by { compute() } // Not allowed: Delegated properties are not allowed in interfaces
  /*...*/
}

最后,我发现您可以通过使用委托创建属性扩展来实现相同的结果:

代码语言:javascript
复制
interface A { /*...*/ }
val A.prop by lazy { compute() }

从使用的角度来看,您只需导入扩展,就可以像往常一样访问a.prop

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43476811

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档