在特质和对象之间进行选择

时间:2019-03-20 05:27:04

标签: scala

我试图在Scala中研究traitobject时,似乎可以使用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)
 }
}

4 个答案:

答案 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种您不需要在范围内真正使用的方法。