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