【问题标题】:Kotlin Singletons: Object vs a Class with private constructorKotlin Singletons:对象与具有私有构造函数的类
【发布时间】:2019-02-02 02:21:53
【问题描述】:

sunflower example app by Google 使用带有伴随对象的私有类来实现其存储库的单例模式,而不是简单地将存储库实现为(固有的单例)对象。

这是我第一次看到在 Kotlin 中以这种方式实现 Singleton,而不是将其实现为 Object。在什么情况下应该使用这个私有构造函数实现而不是更常见的 Object 实现?

class GardenPlantingRepository private constructor(
  private val gardenPlantingDao: GardenPlantingDao
) {
  suspend fun createGardenPlanting(plantId: String) {
    withContext(IO) {
      val gardenPlanting = GardenPlanting(plantId)
      gardenPlantingDao.insertGardenPlanting(gardenPlanting)
    }
  }

  suspend fun removeGardenPlanting(gardenPlanting: GardenPlanting) {
    withContext(IO) {
      gardenPlantingDao.deleteGardenPlanting(gardenPlanting)
    }
  }

  fun getGardenPlantingForPlant(plantId: String) =

    gardenPlantingDao.getGardenPlantingForPlant(plantId)

  fun getGardenPlantings() = gardenPlantingDao.getGardenPlantings()

  fun getPlantAndGardenPlantings() = gardenPlantingDao.getPlantAndGardenPlantings()

  companion object {
    // For Singleton instantiation
    @Volatile private var instance: GardenPlantingRepository? = null

    fun getInstance(gardenPlantingDao: GardenPlantingDao) =
      instance ?: synchronized(this) {
        instance ?: GardenPlantingRepository(gardenPlantingDao).also { instance = it }
      }
  }
}

【问题讨论】:

    标签: kotlin singleton


    【解决方案1】:

    如果你的单例实例需要参数,那么使用object 是一个问题,就像在这种情况下,使用GardenPlantingDao,因为它们不能接受构造函数参数。这在 Android 上经常出现,因为在很多情况下单例需要Context 才能运行。

    可以在这些情况下仍然使用object,但这会不安全或不方便:

    • 第一个选项是在使用任何其他方法之前使用 setter 方法为其提供依赖关系。这意味着所有其他方法都必须检查依赖项是否已初始化,如果没有初始化,则可能会抛出异常,这会导致运行时问题。
    • 或者,您可以要求任何依赖项作为单例的每个方法的参数,这在调用站点很繁琐。

    因此使用私有构造函数和工厂方法来实现单例的“传统”方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-01
      • 2015-06-18
      • 1970-01-01
      相关资源
      最近更新 更多