【问题标题】:What private constructor in Kotlin for?Kotlin 中的私有构造函数是做什么用的?
【发布时间】:2019-12-14 16:27:05
【问题描述】:

我是 Kotlin 的新手。我想问一下 Kotlin 中的私有构造函数是干什么用的? class DontCreateMe private constructor () { /*...*/ }。我的意思是如果我们不能创建它的实例应该是什么类?

【问题讨论】:

  • 如果类只包含静态方法(即在 Kotlin 中有一个伴生对象),或者它应该只由类本身或其伴生对象。例如,参见类 java.util.Optional。您可以创建它的实例。但不是通过调用它的构造函数。只能使用 of() 或 ofNullable() 之类的工厂方法,或者使用 map() 将 Optional 转换为另一个。
  • 签出此链接:refactoring.guru/design-patterns/singleton/java/example,代码在 java 但概念相同
  • 如果你有一个私有的主构造函数,但你有多个公共的辅助构造函数,这样你就可以限制某些参数的组合。
  • "如果该类仅包含静态方法(即在 Kotlin 中有伴随对象)" 在这种情况下,它应该只是 object,而不是具有私有构造函数和所有方法的类在伴随对象内。
  • @AlexeyRomanov 同意。这更像是对 JVM 上的私有构造函数的一般解释。

标签: kotlin constructor


【解决方案1】:

嗯,cmets 中的答案是正确的,但是因为没有人写出完整的答案。我要去试试看。

拥有私有构造函数并不一定意味着对象不能被外部代码使用。这只是意味着外部代码不能直接使用其构造函数,因此它必须通过类范围内的公开 API 获取实例。由于此 API 在类范围内,因此它可以访问私有构造函数。

最简单的例子是:

class ShyPerson private constructor() {
    companion object {
        fun goToParty() : ShyPerson {
            return ShyPerson()
        }
    }
}

fun main(args: String) {
   // outside code is not directly using the constructor
   val person = ShyPerson.goToParty()

   // Just so you can see that you have an instance allocated in memory
   println(person)
}

我见过的最常见的用例是实现单例模式,如 Mojtaba Haddadi 所述,外部代码只能访问该类的一个实例。

一个简单的实现是:

class Unity private constructor() {
    companion object {
        private var INSTANCE : Unity? = null

        // Note that the reason why I've returned nullable type here is
        // because kotlin cannot smart-cast to a non-null type when dealing
        // with mutable values (var), because it could have been set to null 
        // by another thread.
        fun instance() : Unity? {
            if (INSTANCE == null) {
               INSTANCE = Unity()
            } 
            return INSTANCE
        }
    }
}

fun main(args: Array<String>) {
   val instance = Unity.instance()
   println(instance)
}

这通常用于消耗资源的类只被实例化一次,以便整个代码库共享某些数据。

请注意,kotlin 使用 object keyword 来实现此模式,具有线程安全的优势。还有一些开发者考虑Singletons to be an anti-pattern

私有构造函数的另一个用例是实现Builder patterns,其中具有复杂初始化的类可以抽象为更简单的API,因此用户不必处理笨重的构造函数。这个other answer 解决了它在 kotlin 中的用途。

我在现实生活中看到的 kotlin 代码中最简单的用途之一是来自 stdlib 的 Result implementation,它用于更改对象的内部表示。

【讨论】:

    猜你喜欢
    • 2018-04-01
    • 2019-10-16
    • 2011-10-10
    • 2023-03-23
    • 1970-01-01
    相关资源
    最近更新 更多