Kotlin - 私有构造函数的类工厂函数

13

在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()
3个回答

12

您可以这样使用 伴生对象

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

8
你可以像这样做:

你可以这样做:

import MyClass.Companion.myClassOf

class MyClass private constructor() {
    companion object {
        fun myClassOf() = MyClass()
    }
}

//val myInstance1 = MyClass() // not allowed
val myInstance2 = myClassOf()

如果导入了伴生对象,您就不需要使用 MyClass.Companion.myClassOf。我会更新答案以使其更清晰。 - JK Ly
@JKLy 所以我需要导入 Companion 对象或类来引用这个函数。猜测 intArrayOf() 被特殊处理了,不能复制到我的工厂函数中?理想情况下,我希望只需导入类的包而不是类本身。 - Pooch
从技术上讲,IntArray有一个公共的构造函数 - val myIntArray = IntArray()不能编译的原因是该构造函数签名为IntArray(size)。我不认为您可以在没有限定符或导入的情况下调用顶级函数或伴生对象上的函数。 - JK Ly
@Pooch 请注意,导入函数与在Java中执行“import static”几乎相同。 - JK Ly
2
@Pooch 如果你只想导入包并将构造函数设置为“internal”,那么你可以在包级别(例如,在任何类之外)定义该函数。 - Salem
导入Companion完全偏离了创建伴生对象方法的目的,在我看来。@Haim的答案是更好的解决方案,即适当命名它。 - Brandon McAnsh

1
尝试使用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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接