【问题标题】:How do you resolve circular imports in Kotlin你如何解决 Kotlin 中的循环导入
【发布时间】:2023-03-05 05:38:01
【问题描述】:

我是 Kotlin 编程的新手,我已经设法遇到了经典的循环依赖问题 - 我知道 Kotlin 可以应对这些问题,但我想知道如何改变我的设计以避免它。我应该在下面使用哪些结构或 Kotlin 功能?

import MyClass

interface MyInterface {
    fun useMyClass(myInstance: MyClass)
}
import MyInterface

class MyClass(myList: List<MyInterface>) {
    val storedList: List<MyInterface> = myList
    var myValue: Int = 10
}

我希望MyClass 存储多个实现MyInterface 的对象,但我也希望这些对象中的每一个都引用它们已传递给的类,即useMyClass 的每个调用都将具有签名useMyClass(this).

例如,我可以创建一个类

class ImplementingMyInterfaceClass(): MyInterface {
    override fun useMyClass(myInstance: MyClass) {
         myInstance.myValue += 10
    }
}

并在MyClass 内的某个地方调用它:

ImplementingMyInterfaceClass().useMyClass(this)

从技术上讲,我可以在中间创建另一个构造,供MyInterface 使用并由MyClass 继承/实现,但这感觉不正确。有什么建议吗?

注意:在我的具体问题中,将MyInterface 的每个实现视为一种“修饰符”可能会有所帮助(因为它会修改类的实例) - MyClass 实例应该注意它的修饰符和每个修饰符都应该能够修改该实例。

【问题讨论】:

    标签: kotlin design-patterns circular-dependency


    【解决方案1】:

    这在很大程度上取决于接口必须做什么,但您可以将其函数参数限制为 MyClass 实现的某个接口:

    interface MyInterface {
        fun increaseSomeValue(someValueHolder: MySubInterface)
    
        interface MySubInterface {
            var myValue: Int
        }
    }
    
    class MyClass(myList: List<MyInterface>): MyInterface.MySubInterface {
        val storedList: List<myInterface> = myList
        override var myValue: Int = 10
    }
    

    或者你的界面可以接受一个属性参数:

    interface MyInterface {
        fun increaseSomeValue(someValue: KMutableProperty<Int>)
    }
    
    class MyInterfaceImpl: MyInterface {
        override fun increaseSomeValue(someValue: KMutableProperty<Int>) {
            someValue.setter.call(someValue.getter.call() + 10)
        }
    }
    
    // from MyClass:
    storedList.first().printSomeValue(::myValue)
    

    在我们不需要同时获取和设置的其他情况下,采用更通用的函数参数可能更简洁(可以传递 lambda):

    interface MyInterface {
        fun printSomeValue(valueProvider: () -> Int)
    }
    
    class MyInterfaceImpl: MyInterface {
        override fun printSomeValue(valueProvider: () -> Int) {
            println(valueProvider())
        }
    }
    
    // from MyClass:
    storedList.first().printSomeValue(::myValue)
    // or
    storedList.first().printSomeValue { 1..10.random() }
    

    【讨论】:

    • 嘿,谢谢您的回答 :) 我喜欢这些解决方案,但不幸的是,就我而言,接口必须自己访问类实例,而不是访问其中的字段。如果您将接口的每个实现视为一种“修饰符”(因为它将修改类的实例)-myClass 实例应该知道它的修饰符,并且每个修饰符都应该能够修改该实例。我仍在消化您的答案,需要阅读您在此处分享的一些语法,但乍一看,它并未涵盖我的具体问题。
    • 如果没有其他选择,我会接受您的回答,但是,因为它为问题提供了很好的一般指导 - 希望您不介意稍等片刻!
    猜你喜欢
    • 2020-11-01
    • 2020-05-18
    • 2017-11-19
    • 1970-01-01
    • 2021-06-13
    • 1970-01-01
    • 2023-03-29
    • 2016-07-10
    • 1970-01-01
    相关资源
    最近更新 更多