【问题标题】:What is the benefit of having a private constructor and a use a method inside companion object to instantiate a class?拥有私有构造函数并在伴随对象中使用方法来实例化类有什么好处?
【发布时间】:2019-02-13 20:52:55
【问题描述】:

我碰到了这段代码,我不知道为什么有人会这样做。基本上,作者决定将类构造函数设为私有,这样它就不能在文件外实例化,并在类中的伴随对象中添加了一个公共方法,以创建该类的新实例。这种方法有什么好处?

这是我发现的:

class Foo private constructor(private val arg1: Any) {
    //more code here..
    companion object {
        fun newFoo(arg1: Any) = Foo(arg1 = arg1)
    }
}

为什么比这更好?

class Foo(private val arg1: Any) {
    //more code here..
}

【问题讨论】:

  • 一般来说,它允许您稍后更改实现,无论是更改为新的子类型,还是稍后重新构建类的构造函数等等。它还可以让你定义一个更详细的 name 来构造对象,这比类型的名称更详细。
  • 查找“静态工厂方法”。例如,stackoverflow.com/questions/929021/…

标签: kotlin


【解决方案1】:

提供工厂方法而不是公共构造函数有几个好处,包括:

  • 它可以在调用 contrustor 之前进行大量处理。 (如果超类构造函数采用需要计算的参数,这可能很重要。)

  • 它可以在适当的时候返回缓存值而不是新实例。

  • 它可以返回一个子类。 (这允许您将顶级类设为接口,如另一个答案中所述。)确切的类在调用之间可能不同,甚至可以是匿名类型。

  • 它可以有一个名称(如另一个答案中所述)。如果您需要多个方法采用相同的参数,这一点尤其重要。 (例如,可以从直角坐标或极坐标构造的 Point 对象。)但是,工厂方法不需要 特定名称。如果你在伴生对象中实现了invoke()方法,你就可以像构造函数一样调用它。

  • 它可以更轻松地更改类的实现,而不会影响其公共接口。

它还有一个重要的缺点:

  • 子类构造函数不能使用它。

工厂方法在 Kotlin 中的使用似乎比 Java 少,这可能是因为 Kotlin 的主要构造函数和属性的语法更简单。但它们仍然值得考虑——尤其是 Kotlin 伴生对象可以继承。

如需更深入的信息,请参阅 this article,它着眼于 Effective Java 中的建议以及它如何应用于 Kotlin。

【讨论】:

【解决方案2】:

如果你以后想把Foo改成接口,基于该方法的代码将继续工作,因为你可以返回一个仍然实现Foo的具体类,不像不再存在的构造函数。

【讨论】:

    【解决方案3】:

    一个特定于 android 的例子是,Fragment 应该用一个空的构造来构造,并且你想传递给它们的任何数据都应该放在一个 bundle 中。

    我们可以创建一个静态/伴随函数,它接受我们需要为该片段提供的参数,并且该方法将使用空构造函数构造片段并使用捆绑传递数据。

    【讨论】:

      【解决方案4】:

      有很多有用的案例,例如 Kiskae 所描述的。另一个好方法是能够“给你的构造函数命名”:

      class Foo<S: Any, T: Any> private constructor(private val a: S, private val b: T) {
          //more code here...
          companion object {
              fun <S: Any> createForPurposeX(a: S) = Foo(a = a, b = "Default value")
              fun createForPurposeY() = Foo(a = 1, b = 2)
          }
      }
      

      调用站点:

      Foo.createForPurposeX("Hey")
      Foo.createForPurposeY()
      

      注意:您应该使用泛型类型而不是Any

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-23
        • 2021-07-08
        • 1970-01-01
        相关资源
        最近更新 更多