我试图在Scala中研究trait
和object
时,似乎可以使用trait和object来完成类似的任务。
何时使用trait
和何时使用object
的指导原则应该是什么?
编辑: 你们中很多人都在要求一个例子
object PercentileStats {
def addPercentile(df: DataFrame): DataFrame // implementation
}
trait PercentileStats {
def addPercentile(df: DataFrame): DataFrame // implementation
}
有一个可以使用该对象的Process类
object Process {
def doSomething(df: DataFrame): DataFrame {
PercentileStats.addPercentile(df)
}
}
我们也可以使用特质
object Process with PercentileStats {
def doSomething(df: DataFrame): DataFrame {
addPercentile(df)
}
}
答案 0 :(得分:2)
Object-是仅具有一个实例的类。引用时它是惰性创建的,就像一个惰性val。
作为顶级值,对象是单例。
特质-用于在类之间共享接口和字段。
类和对象可以扩展,而特性不能被实例化,因此没有参数。
因此,这意味着如果您更喜欢单例类型实现而没有new instance
发生,那么请使用Object,但是如果您想inherit
实现其他类或对象,则可以使用trait。
答案 1 :(得分:1)
特质:等同于Java中的接口。因此,您可以使用它来定义公共合同,例如Java中的接口。此外,特质可以用于在类之间扩展属性(在方法旁边)。
Scala中的对象实际上非常灵活。用例示例包括:
答案 2 :(得分:0)
我认为这里的真正问题是我在哪里放置独立功能?
共有三个选项。
您可以将独立功能放在外部package
范围内。这样一来,整个package
都可以立即使用它们,但是名称在整个包中必须有意义。
def addPercentile(df: DataFrame): DataFrame // implementation
您可以在object
中将独立功能分组,以提供简单的名称空间。这意味着您必须使用对象的名称来访问函数,但是这会使它们脱离全局名称空间,并且使名称更简单:
object PercentileStats {
def add(df: DataFrame): DataFrame // implementation
}
您可以在trait
中将独立功能分组。这也将它们从package
命名空间中删除,但是允许在没有限定符的情况下从具有该trait
的类中访问它们。但这也使方法在类外部可见,并允许它们被覆盖。为避免这种情况,您应该将它们标记为protected final
:
trait PercentileStats {
protected final def addPercentile(df: DataFrame): DataFrame // implementation
}
选择实际上取决于该函数的使用方式。如果仅在特定范围内使用函数,则将其放在trait
中可能是有意义的,否则其他选项会更好。如果有许多相关功能,则将它们分组在object
中是有意义的。一次性使用的通用功能只需进入package
。
答案 3 :(得分:0)
您还必须考虑如何使用/导入它。
trait Foo {
def test(): String
}
object Bar extends Foo
import Bar._
对象使您可以导入而不是混入类中。
当您要使用scalamock进行模拟时,这是一种救生器。该类混合了很多特征并公开了22种您不需要在范围内真正使用的方法。