Синглтон с аргументом в Котлине
Ссылка Kotlin говорит, что я могу создать синглтон, используя ключевое слово object следующим образом:
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
//
}
}
Тем не менее, я хотел бы передать аргумент этому объекту. Например, ApplicationContext в проекте Android.
Есть ли способ сделать это?
6 ответов
Поскольку объекты не имеют конструкторов, я сделал следующее, чтобы ввести значения при начальной настройке. Вы можете вызывать функцию как хотите, и ее можно вызывать в любое время, чтобы изменить значение (или восстановить синглтон в зависимости от ваших потребностей).
object Singleton {
private var myData: String = ""
fun init(data: String) {
myData = data
}
fun singletonDemo() {
System.out.println("Singleton Data: ${myData}")
}
}
Kotlin имеет функцию, называемую перегрузкой оператора, которая позволяет передавать аргументы непосредственно объекту.
object DataProviderManager {
fun registerDataProvider(provider: String) {
//
}
operator fun invoke(context: ApplicationContext): DataProviderManager {
//...
return this
}
}
//...
val myManager: DataProviderManager = DataProviderManager(someContext)
С большинством существующих ответов можно получить доступ к членам класса без предварительной инициализации синглтона. Вот пример безопасного потока, который гарантирует, что один экземпляр создается перед доступом к любому из его членов.
class MySingleton private constructor(private val param: String) {
companion object {
@Volatile
private var INSTANCE: MySingleton? = null
@Synchronized
fun getInstance(param: String): MySingleton = INSTANCE ?: MySingleton(param).also { INSTANCE = it }
}
fun printParam() {
print("Param: $param")
}
}
Применение:
MySingleton.getInstance("something").printParam()
Есть также две нативные библиотеки инъекций Kotlin, которые довольно просты в использовании и имеют другие формы синглетонов, включая потоки, ключи и т. Д. Не уверен, если это в контексте вашего вопроса, но вот ссылки на оба:
- Injekt (мой, я автор): https://github.com/kohesive/injekt
- Кодеин (похож на Injekt): https://github.com/SalomonBrys/Kodein
Обычно в Android люди используют такую библиотеку или Dagger и др. Для параметризации синглетонов, определения их объема и т. Д.
Я рекомендую вам использовать эту форму для передачи аргументов в siglot в kotlin debit о том, что объект, который ваш конструктор лишен и заблокирован:
object Singleton {
fun instance(context: Context): Singleton {
return this
}
fun SaveData() {}
}
и вы называете это так в деятельности
Singleton.instance(this).SaveData()
Если вы ищете базовый класс SingletonHolder с более чем одним аргументом. Я создал универсальный класс SingletonHolder, который поддерживает создание только одного экземпляра класса singleton с одним аргументом, двумя аргументами и тремя аргументами.
ссылка Github базового класса здесь
Без аргументов (по умолчанию Kotlin):
object AppRepository
Один аргумент (из примера кода по ссылке выше):
class AppRepository private constructor(private val db: Database) {
companion object : SingleArgSingletonHolder<AppRepository, Database>(::AppRepository)
}
// Use
val appRepository = AppRepository.getInstance(db)
Два аргумента:
class AppRepository private constructor(private val db: Database, private val apiService: ApiService) {
companion object : PairArgsSingletonHolder<AppRepository, Database, ApiService>(::AppRepository)
}
// Use
val appRepository = AppRepository.getInstance(db, apiService)
Три аргумента:
class AppRepository private constructor(
private val db: Database,
private val apiService: ApiService,
private val storage : Storage
) {
companion object : TripleArgsSingletonHolder<AppRepository, Database, ApiService, Storage>(::AppRepository)
}
// Use
val appRepository = AppRepository.getInstance(db, apiService, storage)
Более 3-х аргументов:
Чтобы реализовать этот случай, я предлагаю создать объект конфигурации для передачи конструктору синглтона.