Object extends Trait, Class extends Trait, 都必须实现方法

Object extends Trait, Class extends Trait, both have to implement method

我有以下设置:

trait A
{
  def doSomething(): Unit;
}

object B extends A
{
 override def doSomething(): Unit = 
 {
   // Implementation
 }
}

class B(creator: String) extends A
{
 override def doSomething(): Unit =
 {
   B.doSomething() // Now this is just completely unnecessary, but the compiler of course insists upon implementing the method
 }
}

现在你可能想知道我为什么要这样做,为什么我让 class 扩展特征。

问题是,在程序的某处有一个 A 的集合。 所以某处:

private val aList: ListBuffer[A] = new ListBuffer[A]

在那里,我还必须放入 Bs(在其他衍生物中,即 C 和 D)

所以我不能让 B-class 不扩展它。

由于所有实例的实现都相同,我使用对象。

但是我确实需要这个对象也是有原因的。因为有一个class:

abstract class Worker
{
 def getAType(): A

 def do(): Unit =
 {
   getAType().doSomething()
 }
}

class WorkerA
{
  def getAType(): A =
  {
    return B
  }
}

此处返回 B 的 singleton/object。这是在 Worker 中执行 do() 所必需的。

总结一下:

对象 B 是必需的,因为 do() (Worker-Class) 中的通用实现以及 doSomething() 永远不会改变。

class B 是必需的,因为在 BaseType A 的集合中有不同作者的 B 的不同实例。

由于上述原因,对象和 class 都必须实现该特征,所以我在这里陷入了一种进退两难的境地。我找不到看起来更整洁的令人满意的解决方案。

所以,我的问题是(事实证明,作为一个非母语人士,我应该更清楚地说明这一点)

有什么方法可以让 class 扩展特征(或 class)并说明应该在对象中而不是 [=70= 中查找任何抽象方法实现],以便我只能(在对象中)实现一次 "doSomething()"(来自特征)?正如我所说,特质在这里完成了两个不同的任务。 一个是 BaseType,以便集合可以获得 class 的实例。另一个是确保每个对象中都存在 doSomething() 方法的合同。

所以对象 B 需要 扩展特征,因为特征就像一个 Java 接口和每个(!)对象 B(或 C,或 D ) 需要 拥有该方法。 (所以我看到的唯一选项 -> 定义一个 interface/trait 并确保该方法存在)

编辑:以防万一有人想知道。我是如何真正解决问题的:我实现了两个特征。

现在,对于一个 class(在我需要的地方),我扩展两个,而对于另一个,我只扩展一个。所以我实际上从来不需要实现任何不是绝对必要的方法:)

正如我在评论部分所写,我真的不清楚你在问什么。 但是,查看您的代码示例,在我看来 trait A 并不是真正需要的。 您可以使用 Scala SDK 自带的类型:

object B extends (()=>Unit) {
  def apply() { /* implementation */ }
}

或者,作为变体:

object B {
  val aType:()=>Unit = {() => /* implementation */ }
}

在第一种情况下,您可以使用 B 访问单例实例,在第二种情况下使用 B.aType。 在第二种情况下,不需要显式声明 apply 方法。

选择你喜欢的。 基本信息是:如果您只定义一个简单的方法,则不需要特性。 这就是 Scala 函数的用途。

列表类型可能如下所示:

private val aList:ListBuffer[()=>Unit] = ???

(顺便说一句:为什么不将其声明为 Seq[()=>Unit]?它是 ListBuffer 而不是其他类型的序列对调用者来说很重要吗?)

你的员工可能看起来像这样:

abstract class Worker {
  def aType:()=>Unit // no need for the `get` prefix here, or the empty parameter list
  def do() {aType()}
}

请注意,现在 Worker 类型已变为 class,它提供了调用函数的方法。 所以,真的没有必要Workerclass。 您可以直接获取函数 (aType) 并调用它,就这样。

如果您总是想调用 object B 中的实现,那么 - 那就那样做吧。 无需将调用包装在其他类型的实例中。 您的示例 class B 只是将调用转发给 B 对象,这确实是不必要的。 甚至不需要创建 B 的实例。 它确实有私有成员变量 creator,但由于从未使用过,因此永远不会以任何方式访问它。

所以,我建议完全删除 class B。 您所需要的只是类型 ()=>Unit,这正是您所需要的:一个不带参数且 returns 什么都没有的函数。

如果你厌倦了一直写()=>Unit,你可以定义一个类型别名,例如在包对象中。 这是我的建议:

type SideEffect = ()=>Unit

然后你可以使用SideEffect作为()=>Unit的别名。

我只能做到这些。 在我看来,这可能不是您想要的。 但也许这会对你有所帮助。 如果你想有一个更具体的答案,如果你能把问题弄清楚就好了。

object B 除了一些特殊规则外,与 class B 并没有太大关系。

如果您希望重用 doSomething 方法,您应该重用对象的实现:

class B {
  def doSomething() = B.doSomething()
}

如果要将 object B 指定为 class B 的特定实例,则应执行以下操作:

object B extends B("some particular creator") {
...
}

您也不需要 override 修饰符,尽管它们可以方便地进行编译器检查。

伴随对象 扩展特征的概念对于定义与 class 本身相关的行为(例如静态方法)很有用,而不是 class。换句话说,它允许您的静态方法实现接口。这是一个例子:

import java.nio.ByteBuffer

// a trait to be implemented by the companion object of a class
// to convey the fixed size of any instance of that class
trait Sized { def size: Int }

// create a buffer based on the size information provided by the
// companion object
def createBuffer(sized: Sized): ByteBuffer = ByteBuffer.allocate(sized.size)

class MyClass(x: Long) {
  def writeTo(buffer: ByteBuffer) { buffer.putLong(x) }
}
object MyClass extends Sized {
  def size = java.lang.Long.SIZE / java.lang.Byte.SIZE
}

// create a buffer with correct sizing for MyClass whose companion
// object implements Sized. Note that we don't need an instance
// of MyClass to obtain sizing information.
val buf = createBuffer(MyClass)

// write an instance of MyClass to the buffer.
val c = new MyClass(42)
c.writeTo(buf)