代码之家  ›  专栏  ›  技术社区  ›  Johann

返回对其函数中的单例类实例的引用

  •  0
  • Johann  · 技术社区  · 6 年前

    在下面的代码中,我想设置对类实例的引用,以便静态函数可以返回对它的引用:

    open class TestRunner {
    
        init {
            instance = this
        }
    
        companion object {
            private lateinit var instance: TestRunner
    
            fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner {
               for (setup in testSetups) {
                  testsSetups.add(setup)
               }
    
               return instance
            }
        }
    }
    

    但是设置 instance = this 不允许。如何从函数返回类的实例,同时将类保持为单例?

    1 回复  |  直到 6 年前
        1
  •  0
  •   IlyaMuravjov    6 年前

    如果我说对了,你想要这样的东西:

    abstract class TestRunner {
        companion object : TestRunner()
    }
    
        2
  •  0
  •   Johann    6 年前

    这似乎管用。只需引用类的名称就足够了,而不必保留对类的引用的变量。但是,若要从函数返回类的实例,返回类型必须是同伴:

    open class TestRunner {
        companion object {
            fun addTestSetups(vararg testSetups: () -> TestSetup): Companion {
               for (setup in testSetups) {
                  testsSetups.add(setup)
               }
    
               return TestRunner
            }
        }
    }
    

    这不是真正的单例,因为如果执行以下操作,您仍然可以创建新实例:

    val testRunner = TestRunner()
    

    但是,如果您从未创建实例,而只是静态地引用函数,那么它的行为确实像一个单例,并且伴生对象中的任何私有变量的状态仍将保持不变。

    更新:

    我在Android开发人员网站上看到了这段代码,它显示了一个设置为singleton的类的示例:

    class StockLiveData(symbol: String) : LiveData<BigDecimal>() {
        private val stockManager: StockManager = StockManager(symbol)
    
        private val listener = { price: BigDecimal ->
            value = price
        }
    
        override fun onActive() {
            stockManager.requestPriceUpdates(listener)
        }
    
        override fun onInactive() {
            stockManager.removeUpdates(listener)
        }
    
        companion object {
            private lateinit var sInstance: StockLiveData
    
            @MainThread
            fun get(symbol: String): StockLiveData {
                sInstance = if (::sInstance.isInitialized) sInstance else StockLiveData(symbol)
                return sInstance
            }
        }
    }
    

    但应该指出的是,这个例子需要函数首先返回一个实例来检查是否设置了实例变量,如果没有,则创建一个新实例。我不知道这是什么意思,因为调用函数你已经有一个实例。那么为什么还要创建一个新实例呢?似乎没有任何意义。

        3
  •  0
  •   Tenfour04    6 年前

    object 在Kotlin中是singleton,而不是它在其中定义的类。一个伴生对象有额外的便利,允许您通过外部类的名称来调用它。但在其他方面,它与之没有等级制度。

    要使类成为子类,不能在伴生对象中定义函数。但是您可以使类成为抽象类,因此除非子类化,否则无法实例化它。然后让您的同伴对象扩展抽象类,使其具有所有可用的函数。

    abstract class TestRunner{
        open fun addTestSetups(vararg testSetups: () -> TestSetup): TestRunner{
            //...
            return this
        }
    
        companion object: TestRunner()
    }
    

    用法:

    TestRunner.addTestSetups(someTestSetup)
    

    注意,您的singleton不是TestRunner的实例。它是TestRunner子类的单例实例。但是由于没有定义额外的函数,也没有重写任何内容,所以它的行为与TestRunner完全一样。

    如果你想要一个子类:

    abstract class ExtendedTestRunner: TestRunner() {
    
        fun someOtherFunction() {}
    
        companion object: ExtendedTestRunner()
    }
    

    同伴不是子类,但他们抽象的父母可以是。