繁体   English   中英

对象扩展特性,类扩展特性,都必须实现方法

[英]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
 }
}

现在您可能想知道为什么我什至这样做,为什么我还要让班级也扩展特质。

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

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

在那儿,我还必须放入Bs(以及其他派生词C和D)

所以我不能只是让B级不扩展它。

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

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

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)都需要具有该方法。 (因此,我看到的唯一选项是->定义接口/特征并确保该方法在那里)

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

现在,对于一个班级(我需要的地方),我将两者都扩展,而对于另一个班级,我只会扩展一个。 因此,我实际上不必执行并非绝对必要的任何方法:)

正如我在评论部分中所写的那样,我真的不清楚您要问什么。 但是,在您的代码示例中,对我来说似乎并没有真正需要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的实例。 它确实具有private成员变量creator ,但由于从未使用过,因此绝不会以任何方式对其进行访问。

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

如果您一直不厌烦编写()=>Unit ,则可以定义类型别名,例如在package对象内部。 这是我的建议:

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修饰符,尽管它们可以方便地进行编译器检查。

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

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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM