2013-05-20 37 views
1

情况:案例类和继承:如何提供不同的行为

trait Operation { 
def something: Double 
} 

trait OperationPlus { this: A => 
override def something: Double = x + y 
} 
trait OperationMinus { this: A => 
    override def something: Double = x - y 
} 

case class A(x: Double, y: Double) { this: Operation => 
} 

val a = new A(1.0, 2.0) with OperationPlus 
    println(a.something) 

错误:

class A cannot be instantiated because it does not conform to its self-type A with Operation 

而且,我不能实例A.

我尝试多种不同的方法,但没有提供我在找什么。我不想使用案例类继承,或放弃案例类,理想情况下特质/自我类型/其他应该做的伎俩。有任何想法吗?

更新 优选溶液

trait Operation { this: A => 
def something: Double 
} 

trait OperationPlus extends Operation { this: A => 
    override def something: Double = x + y 
} 
trait OperationMinus extends Operation { this: A => 
    override def something: Double = x - y 
} 

abstract case class A(val x: Double, val y: Double) extends Operation 

val a = new A(1.0, 2.0) with OperationPlus 
println(a.something) 

val b = new A(1.0, 2.0) with OperationMinus 
println(b.something) 

可能的解决方案1:

trait Operation { 
    def x:Double 
    def y:Double 
    def something: Double 
} 

trait OperationPlus extends Operation { 
    override def something: Double = x + y 
} 
trait OperationMinus extends Operation { 
     override def something: Double = x - y 
} 

abstract case class A(val x: Double, val y: Double) extends Operation 

通过使用常规类,简单性状遗传和自型中的实际值可以定义它并动态地提供行为。

不幸的是,我不得不重新定义特质中的字段。我想是公平的妥协。会有兴趣知道是否有人知道另一种方法。

感谢

回答

2

不知道关于你的使用情况,但你需要定义A类这样的,如果你想使其工作:

abstract case class A(x: Double, y: Double) extends Operation 

但我不认为这是非常地道的做法用例类。它们主要用作数据容器,通常不包含任何行为。 (也许你可以告诉一些事情的更多信息,你想用这个来实现)

+0

感谢@tenshi,如果我做的情况下抽象类,我将无法进行实例化。我想要做的是一个经典的面向对象的父类,并为每个子类定义一个方法。然而,这些方法可以被不同的层次重复使用,所以我想使它成为一个基本特征。我无法找到如何提取出来。 – fracca

+0

@fracca你仍然可以通过在一些操作中混合实例化:'new A(1.0,2.0)和OperationMinus'。但是在你的示例方法中,'something'是抽象的,所以你需要定义它或者让整个类变得抽象。或者,您可以直接在'A'类中扩展'OperationMinus'或'OperationPlus',并且不要声明它是抽象的。 – tenshi

+0

抽象案例类有效地允许我们保留案例类的好处加上行为混合。但是,因为某些操作是基于A定义的,所以我需要重新定义字段x和y。 – fracca

2

首先,你应该有:

trait OperationPlus extends Operation 
trait OperationMinus extends Operation 

其次,你不能定义A作为案例类,因为这自动定义apply方法在伴随对象上,其中new A被调用(带参数)。由于错误的自我类型(您看到的错误),此调用失败。

删除case。如果你需要模式匹配,定义自己的提取(实施unapply):

class A(val x: Double, val y: Double) { this: Operation => } 

object A { 
    def unapply(v: A) = Some((v.x, v.y)) 
}