Object扩展了Trait,Class扩展了Trait,两者都必须实现方法

时间:2015-07-15 21:01:57

标签: scala object collections singleton traits

我有以下设置:

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

现在你可能想知道我为什么要这样做,为什么我让这个课程也扩展了这个特性。

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

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

并且在那里,我还必须把Bs(以及其他衍生物,即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()所必需的。

总结:

由于do()(Worker-Class)中的泛型实现以及doSomething()永远不会更改,因此需要对象B.

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

由于上述原因,对象和类都必须实现这个特性,所以我在这里处于两难境地。我找不到一个看起来更整洁的令人满意的解决方案。

所以,我的问题是(事实证明,作为非本地人,我应该更多地澄清这一点)

有没有办法让一个类扩展一个特征(或类),并说任何抽象方法实现应该在对象而不是类中查找,这样我只能实现“doSomething()”(从特质)一次(在对象中)?正如我所说,这个特质在这里完成了两个不同的任务。 一个是BaseType,以便集合可以获取类的实例。另一个是确保每个对象都有doSomething()方法的契约。

因此,对象B 需要来扩展特征,因为特征就像一个Java接口而且每个(!)对象B(或者C或D)需要有这种方法。 (所以我看到的唯一选择 - >定义一个接口/特性并确保方法在那里)

修改:如果有人想知道。我是如何真正解决问题的:我实现了两个特征。

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

3 个答案:

答案 0 :(得分:2)

正如我在评论部分写的那样,我真的不清楚你在问什么。 但是,查看代码示例,在我看来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类型已成为一个提供调用函数的方法的类。 所以,实际上没有必要有Worker类。 您可以直接使用函数(aType)并调用它,就这样。

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

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

如果您厌倦了一直编写()=>Unit,您可以定义类型别名,例如在包对象内。 这是我的推荐:

type SideEffect = ()=>Unit

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

这就是我能做到的一切。 在我看来,这可能不是你想要的。 但也许这会对你有所帮助。 如果你想得到一个更具体的答案,那么如果你澄清这个问题会很好。

答案 1 :(得分:2)

除了一些特殊规则之外,

object Bclass B没什么关系。

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

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

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

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

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

答案 2 :(得分:0)

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

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)