我有以下设置:
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 B
和class 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)