The sunflower example app by Google uses a private Class with a companion object to implement a Singleton pattern of their repository instead of simply implementing the repository as an (inherently Singleton) Object.
This is the first time I've seen a Singleton implemented this way in Kotlin instead of implementing it as an Object. In what context(s) should this private constructor implementation be used instead of the more common Object implementation?
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 }
}
}
}
Using an object is an issue if your singleton instance needs parameters, like in this case here, with GardenPlantingDao, as they cannot take constructor arguments. This comes up frequently on Android, as there's many cases where singletons requires a Context to operate.
You could still use an object in these cases, but it would either be unsafe or inconvenient:
Hence the "traditional" way of implementing a singleton with a private constructor and a factory method instead.