对象扩展Trait,类扩展Trait,两者都必须实现方法



我有以下设置:

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
 }
}

现在你可能想知道我为什么要这样做,为什么我让类也扩展这个trait。

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

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

在这里,我还必须把b(在其他衍生物中,即C和D)

所以我不能让b类不扩展它

由于所有实例的实现都是相同的,所以我希望使用Object。

但是还有一个原因,我真的需要这个对象。因为有一个类:

abstract class Worker
{
 def getAType(): A
 def do(): Unit =
 {
   getAType().doSomething()
 }
}
class WorkerA
{
  def getAType(): A =
  {
    return B
  }
}

这里返回B的单例/对象。这是在Worker中实现do()所需要的。

总结:

需要对象B是因为do() (Worker-Class)中的泛型实现,也因为doSomething()永远不会改变。

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

由于上述原因,对象和类都必须实现trait,我在这里陷入了两难境地。我找不到比这更令人满意的解决方案了。

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

有没有办法让一个类扩展一个trait(或类),并说任何抽象方法的实现应该在对象而不是类中查找,这样我就必须只实现"doSomething()"(从特质中)一次(在对象中)?就像我说的,这个特征在这里完成了两个不同的任务。一个是BaseType,以便集合可以获得类的实例。另一个是确保doSomething()方法存在于每个对象中的契约。

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

edit:如果有人想知道。我是如何解决这个问题的:我实现了两个特性。

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

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

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

或者,作为变体:

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

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

挑你喜欢的。关键信息是:如果只定义一个简单的方法,就不需要trait。这就是Scala函数的作用。

列表类型可能像这样:

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

你的worker可能看起来像这样:

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

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

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

所以,我建议完全删除class B。您所需要的只是类型()=>Unit,这正是您所需要的:一个不接受参数且不返回任何值的函数。

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

type SideEffect = ()=>Unit

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

这就是我所能做的。在我看来,这可能不是你要找的东西。但也许这对你们的学习有帮助。如果你想要一个更具体的答案,最好能把问题说清楚。

除了一些特殊的规则,object Bclass B并没有太多的关系。

如果你想重用doSomething方法,你应该重用对象的实现:

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

如果您想指定object B作为class B的特定实例,那么您应该执行以下操作:

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

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

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

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)