我碰到了这段代码,我不确定为什么有人会这样做。基本上,作者决定将类构造函数设为私有,以便无法在文件外部对其进行实例化,并向该类中的同伴对象添加了一个公共方法,以创建该类的新实例。这种方法有什么好处?
这是我发现的:
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..
}
答案 0 :(得分:2)
提供工厂方法而不是公共构造函数有很多好处,包括:
在调用委托人之前,它可以做很多处理。 (如果超类构造函数使用需要计算的参数,这可能很重要。)
它可以返回缓存的值,而不是适当的新实例。
它可以返回一个子类。 (这使您可以将顶级类作为接口,如另一个答案所述。)确切的类可以在调用之间有所不同,甚至可以是匿名类型。
它可以有一个名称(如另一个答案中所述)。如果您需要采用相同参数的多种方法,则这一点尤其重要。 (例如,可以由矩形或极坐标构造的Point对象。)但是,factory方法不需要 特定的名称;如果在随播对象中实现invoke()
方法,则可以使用与构造函数完全相同的方法来调用它。
它使更改类的实现变得更容易,而又不影响其公共接口。
它也有一个重要的缺点:
在Kotlin中,工厂方法似乎比Java少使用,这可能是由于Kotlin对主要构造函数和属性使用的语法更简单。但是它们仍然值得考虑-特别是因为Kotlin伴随对象可以继承。
有关更多信息,请参见this article,其中介绍了 Effective Java 中的建议以及该建议如何应用于Kotlin。
答案 1 :(得分:1)
如果将来您想将Foo
更改为接口,则基于该方法的代码将继续起作用,因为您可以返回仍实现Foo
的具体类,这与构造函数不同。已经存在了。
答案 2 :(得分:0)
一个特定于android的示例是,Fragments应该使用空构造来构造,并且您想要传递给它们的任何数据都应该放在一个包中。
我们可以创建一个static / companion函数,该函数接受该片段所需的参数,此方法将使用空的构造函数构造该片段,并使用包传递数据。
答案 3 :(得分:0)
有很多有用的案例,例如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
。