Kotlin中带参数的Singleton

Kotlin中带参数的Singleton,kotlin,Kotlin,上面说我可以使用object关键字创建一个singleton,如下所示: object DataProviderManager { fun registerDataProvider(provider: DataProvider) { // } } 但是,我想向该对象传递一个参数。例如,Android项目中的ApplicationContext 有什么方法可以做到这一点吗?因为对象没有构造函数,所以我在初始设置中注入了以下值。您可以随意调用该函数,并且可以随时调用该函数来修改值(

上面说我可以使用object关键字创建一个singleton,如下所示:

object DataProviderManager {
  fun registerDataProvider(provider: DataProvider) {
    //
  }
}
但是,我想向该对象传递一个参数。例如,Android项目中的ApplicationContext


有什么方法可以做到这一点吗?

因为对象没有构造函数,所以我在初始设置中注入了以下值。您可以随意调用该函数,并且可以随时调用该函数来修改值(或根据需要重新构造单例)


还有两个本机Kotlin注入库非常易于使用,并具有其他形式的单例,包括每线程、基于键等。不确定是否在您的问题的上下文中,但这里有指向这两个库的链接:

  • Injekt(我的,我是作者):
  • Kodein(类似于Injekt):

通常在Android中,人们使用这样的库,或Dagger等来完成单例的参数化、范围界定等。Kotlin有一个名为的功能,允许您将参数直接传递给对象

object DataProviderManager {
  fun registerDataProvider(provider: String) {
      //
  }

  operator fun invoke(context: ApplicationContext): DataProviderManager {
      //...
      return this
  }
}

//...
val myManager: DataProviderManager = DataProviderManager(someContext)

我建议您使用此表单在Kotlin debit中的singleton中传递参数,说明构造函数中的对象被剥夺和阻止:

object Singleton {

    fun instance(context: Context): Singleton {
        return this
    }

    fun SaveData() {}
}
你在活动中这样称呼它

Singleton.instance(this).SaveData()

对于大多数现有答案,可以在不首先初始化单例的情况下访问类成员。下面是一个线程安全示例,确保在访问其任何成员之前创建一个实例

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()

如果您正在寻找具有多个参数的基本SingletonHolder类。我创建了SingletonHolder泛型类,它只支持创建一个带有一个参数、两个参数和三个参数的singleton类实例

非参数(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)
一个参数(来自上面链接中的示例代码):

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)
class AppRepository私有构造函数(private val db:Database){
伴生对象:SingleArgSingletonHolder(::AppRepository)
}
//使用
val appRepository=appRepository.getInstance(db)
两个参数:

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)
class AppRepository私有构造函数(私有val db:数据库,私有val apiService:apiService){
伴生对象:PairArgSingleTonHolder(::AppRepository)
}
//使用
val appRepository=appRepository.getInstance(db,apiService)
三个参数:

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)
class AppRepository私有构造函数(
私有val数据库:,
私人增值服务:增值服务,
专用val存储:存储
) {
伴生对象:三耳单音持有人(::AppRepository)
}
//使用
val appRepository=appRepository.getInstance(数据库、apiService、存储)
超过3个参数:

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)

为了实现这种情况,我建议创建一个config对象来传递给singleton构造函数。

这与Jeremy的解决方案相同,但语法不同。单例仍然是在没有任何参数的情况下创建的。如果希望它像构造函数一样工作,只需返回
this
。我已经更新了答案,证明了这一点。好吧,但是什么阻止你在不调用
invoke
方法的情况下使用对象呢?这个答案有几个大缺点。首先,调用方可能忘记调用
init
。第二个是参数存储在
var
中,这意味着以后可能会错误地更改它,通常在单例中,您不希望以后修改构造期间所需的内容。第三,这个答案甚至没有使用方法链接,这让使用起来很痛苦。这个答案不是这个问题的最佳实践,正如@Sature9Nine所说,这很好,但使用
对象
的主要原因是要消除这个同步的单例创建代码。不,此示例不正确,因为您仍然可以在初始化之前调用
Singleton.SaveData()
。您还可以随时更改注入的参数,这不是单例所能做到的——除非特别需要。