我有以下设置:
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)需要有这种方法。 (所以我看到的唯一选择 - >定义一个接口/特性并确保方法在那里)
修改:如果有人想知道。我是如何真正解决问题的:我实现了两个特征。
现在对于一个类(我需要它),我扩展了两个,而另一个我只扩展了一个。所以我实际上从来没有必要实现任何非必要的方法:)
答案 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 B
与class 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)