伴随对象实现接口的可能性的好处
Companion objects benefits of posibility to implement interfaces
为什么在Kotlin/Scala companion objects 中可以实现一些接口,这有什么好处?什么时候使用这个功能有用?
当您在程序中只需要特定 class 的一个实例时,您可以使用单例对象。
例如Scala 的 Nil
实现 List[Nothing]
。不是每种类型的列表都需要实现 它是特殊的 Nil
只有其中一个。
在typeclass pattern中,您只有一个implicit object
用于相应的实现。
此外,在 Java 中创建 public static Something
的地方,您会在伴随对象中创建它。
我个人发现它们对于实现 sbt 插件很有用,该插件将 object Blah extends Renderable
渲染到文件 blah.html
。找到更多关于实用性的信息 here。我 必须知道它实现了 这个特征!
因为companion object
s是object
s,object
s可以实现接口(或扩展classes),没有充分的理由禁止它特别是 companion object
s。
Scala 中的一个常见用途是工厂:例如Seq
、List
、Vector
等伴随对象都扩展了 TraversableFactory
,因此您可以编写使用 TraversableFactory
的代码并传递其中任何一个来构造类型你要。例如
def build[CC[X] <: Traversable[X] with GenericTraversableTemplate[X, CC], A](factory: TraversableFactory[CC])(elems: A*) = factory(elems)
// build(List)(1,2,3) == List(1, 2, 3)
// build(Set)(1,2,3) == Set(1, 2, 3)
同样,所有 case class 伴随对象都扩展了函数类型。
您可以使用 companion object
s 和继承来实现某种级别的 class-lavel 或静态多态性。
示例 1:工厂
考虑一个接口
interface Factory<T> {
fun create(): T
}
现在,我们创建一个 class 其伴随对象实现它
class Foo {
companion object: Factory<Foo> {
override fun create() = Foo()
}
}
现在我们可以为所有工厂创建一个扩展函数,例如记录对象。
fun <T> Factory<T>.createAndLog(): T {
val t = create()
println(t)
return t
}
像这样使用它
Foo.createAndLog()
示例 2:查询
考虑一个标记界面
interface Queryable<T>
我们现在有两个 classes User
和 Article
表示数据库中的表,其 companion object
实现了接口。
class User(val id: String) {
companion object: Queryable<User> {}
}
class Article(val authorId: String) {
companion object: : Queryable<Article> {}
}
我们现在可以定义一个扩展函数来从 class
创建一个查询
fun <T> Queryable<T>.query() = db.createQuery<T>()
我们可以称之为
User.query()
//or
Article.query()
为什么在Kotlin/Scala companion objects 中可以实现一些接口,这有什么好处?什么时候使用这个功能有用?
当您在程序中只需要特定 class 的一个实例时,您可以使用单例对象。
例如Scala 的 Nil
实现 List[Nothing]
。不是每种类型的列表都需要实现 它是特殊的 Nil
只有其中一个。
在typeclass pattern中,您只有一个implicit object
用于相应的实现。
此外,在 Java 中创建 public static Something
的地方,您会在伴随对象中创建它。
我个人发现它们对于实现 sbt 插件很有用,该插件将 object Blah extends Renderable
渲染到文件 blah.html
。找到更多关于实用性的信息 here。我 必须知道它实现了 这个特征!
因为companion object
s是object
s,object
s可以实现接口(或扩展classes),没有充分的理由禁止它特别是 companion object
s。
Scala 中的一个常见用途是工厂:例如Seq
、List
、Vector
等伴随对象都扩展了 TraversableFactory
,因此您可以编写使用 TraversableFactory
的代码并传递其中任何一个来构造类型你要。例如
def build[CC[X] <: Traversable[X] with GenericTraversableTemplate[X, CC], A](factory: TraversableFactory[CC])(elems: A*) = factory(elems)
// build(List)(1,2,3) == List(1, 2, 3)
// build(Set)(1,2,3) == Set(1, 2, 3)
同样,所有 case class 伴随对象都扩展了函数类型。
您可以使用 companion object
s 和继承来实现某种级别的 class-lavel 或静态多态性。
示例 1:工厂
考虑一个接口
interface Factory<T> {
fun create(): T
}
现在,我们创建一个 class 其伴随对象实现它
class Foo {
companion object: Factory<Foo> {
override fun create() = Foo()
}
}
现在我们可以为所有工厂创建一个扩展函数,例如记录对象。
fun <T> Factory<T>.createAndLog(): T {
val t = create()
println(t)
return t
}
像这样使用它
Foo.createAndLog()
示例 2:查询
考虑一个标记界面
interface Queryable<T>
我们现在有两个 classes User
和 Article
表示数据库中的表,其 companion object
实现了接口。
class User(val id: String) {
companion object: Queryable<User> {}
}
class Article(val authorId: String) {
companion object: : Queryable<Article> {}
}
我们现在可以定义一个扩展函数来从 class
创建一个查询fun <T> Queryable<T>.query() = db.createQuery<T>()
我们可以称之为
User.query()
//or
Article.query()