【问题标题】:Kotlin - Factory Function for Class with Private ConstructorKotlin - 具有私有构造函数的类的工厂函数
【发布时间】:2019-08-20 19:10:17
【问题描述】:

在 Kotlin 中,是否可以有一个工厂函数来创建具有私有构造函数的类的实例?

我的目标是强制使用工厂函数并防止通过类的构造函数进行实例化。

例子:

// factory function, valid
val myInstance = myClassOf()

// class instantiation, invalid
val myInstance = MyClass()

我正在尝试模仿一些内置工厂函数的行为,例如 intArrayOf(),例如

// works
val myIntArray = intArrayOf()

// not possible as IntArray has a private constructor
val myIntArray = IntArray()

【问题讨论】:

    标签: kotlin


    【解决方案1】:

    你可以这样使用companion object

    class MyClass private constructor() {
      companion object {
        operator fun invoke() = MyClass()
      }
    }
    
    val myInstance = MyClass() // Calls the factory function invoke()
    

    如果工厂函数有特殊含义,请为其命名。例如:

    class MyClass private constructor(values: List<String>) {
      companion object {
        fun of(vararg values: String) = MyClass(values.toList())
      }
    }
    
    val myInstance = MyClass.of("first", "second")
    

    【讨论】:

      【解决方案2】:

      你可以这样做:

      import MyClass.Companion.myClassOf
      
      class MyClass private constructor() {
          companion object {
              fun myClassOf() = MyClass()
          }
      }
      
      //val myInstance1 = MyClass() // not allowed
      val myInstance2 = myClassOf()
      

      【讨论】:

      • 如果您导入伴随对象,则不需要:MyClass.Companion.myClassOf - 我将更新答案以使其更清晰
      • @JKLy 所以我需要导入 Companion 对象或类来引用这个函数。猜测intArrayOf() 被给予特殊处理并且不能复制到我自己的工厂功能?理想情况下,我希望能够只导入类的包而不是类本身。
      • 技术上IntArray 有一个公共构造函数——val myIntArray = IntArray() 不能编译的原因是因为构造函数有签名IntArray(size)。我不相信你可以在没有限定或导入的情况下调用顶级函数或 Companion 对象上的函数。
      • @Pooch 还请注意,必须导入函数与在 Java 中执行 import static 几乎相同。
      • @Pooch 如果您只想导入包并创建构造函数internal,则可以在包级别定义函数(例如,在任何类之外),如果这适合您的需要。
      【解决方案3】:

      改用 Builder。

      class FoodOrder private constructor(
        val bread: String?,
        val condiments: String?,
        val meat: String?,
        val fish: String?) {
      
          data class Builder(
            var bread: String? = null,
            var condiments: String? = null,
            var meat: String? = null,
            var fish: String? = null) {
      
              fun bread(bread: String) = apply { this.bread = bread }
              fun condiments(condiments: String) = apply { this.condiments = condiments }
              fun meat(meat: String) = apply { this.meat = meat }
              fun fish(fish: String) = apply { this.fish = fish }
              fun build() = FoodOrder(bread, condiments, meat, fish)
          }
      }
      

      参考:https://www.baeldung.com/kotlin-builder-pattern

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-24
        相关资源
        最近更新 更多