Kotlin单例在子类中

时间:2018-08-04 12:56:48

标签: inheritance kotlin singleton

我正在编写一个框架,在其中难以编写需要由用户专用的通用单例类。

我希望用户能够编写如下内容:

class CustomClass protected constructor() : BasicClass()

该框架能够编写:

BasicClass.instance

返回BasicClass单例

并且用户能够写:

CustomClass.instance

返回相同的实例,但作为CustomClass单例实例。

我想到了两种可能性

案例1:单身人士由班级用户管理

class CustomClass private constructor() : BasicClass() {
    private object Holder {
        val INSTANCE = CustomClass()
    }

    companion object {
        val instance: CustomClass by lazy {
            Holder.INSTANCE
        }
    }
}

但是我在BasicClass方面没有实例引用,用户每次都需要实现单例。

案例2:Singleton由框架管理 我无法正确编写

预先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

这里开箱即用,特别是因为实际上没有多少上下文需要这些类的外观。基本上,如果您希望框架处理单例,则需要执行以下两项操作之一:

  1. 自动发现BasicClass的实现(在运行时,或者带​​有批注并进行代码生成)
  2. 为用户提供一种明确设置实现类的方式

这可能是2的实现。

// This is the class that users of the framework want to extend
abstract class BasicClass

// This is the way both the framework and users can access the singleton instance
object Singleton {

    // The way users can set how an instance of the desired class is constructed
    var provider: (() -> BasicClass)? = null
        set(value) {
            if (field == null) {
                field = value
            } else {
                throw IllegalStateException("You can only register one provider for Singleton")
            }
        }

    val value: BasicClass by lazy {
        provider
                ?.invoke()
                ?: throw IllegalStateException("You need to declare your instance provider")
    }

    inline fun <reified T : BasicClass> get(): T {
        return value as? T
                ?: throw NullPointerException("Instance is of wrong type ${value.javaClass.name}")
    }
}

现在,您框架的用户可以执行以下操作:

class CustomClass private constructor() : BasicClass() {
    companion object {
        val instanceProvider: () -> BasicClass = { CustomClass() }
    }
}

并且,根据他们代码的生命周期,他们可以将类注册为

ClassInstance.provider = CustomClass.instanceProvider

最后,在您的框架中,您可以执行以下操作:

val basic: BasicClass = ClassInstance.get()

用户可以同时执行以下操作:

val basic: BasicClass = ClassInstance.get()
val custom: CustomClass = ClassInstance.get()