2011-11-05 89 views
2

我在继承和scala下界有一些问题;我会尝试用一个例子来解释一下: 我有一类人用类似的签名:斯卡拉继承和下界问题

def doSomething[P<%Person](persons :List[P]) { 
} 

我还创建了一个子类工人,他的方法DoSomething的是这样的:

override def doSomething(persons: List[Worker]) { 
} 

但是,这引发了一个错误,指出Worker.doSomething()不会覆盖任何东西?

回答

3

你不能继承这种方式。它违反了Liskov Substitution Principle。我会说明为什么是这样。假设你可以编译这些类:现在

class Person { 
    def doSomething[P<%Person](persons :List[P]) { 
    } 
} 

class Worker extends Person { 
    override def doSomething(persons: List[Worker]) { 
    } 
} 

,这个简单的程序会失败:

val p1: Person = new Worker 
val p2: Person = new Person 
p1.doSomething(List(p2)) 

由于p2不是Worker,这一呼吁是无效的。但是,由于p1Person,该呼叫有效!这个矛盾是你提出的推翻的结果。

但它比这更糟糕!这也将无法正常工作:

p1.doSomething[Worker](List(p1)) 

现在,即使它是通过工人的名单,由p1如预期,因为在doSomethingWorker不指望一个类型参数失败。但是,Person的方法doSomething声明应该传递一个类型参数!再一次,这个矛盾是你提出的推翻的结果。

请记住,继承是is-a种关系。如果WorkerPerson,那么它应该动作Person一样,期望Person行动的所有方式。如果这不是你想要创建的那种关系,那么就不要使用继承。

4

一个特定的方法不能覆盖泛型方法(虽然特定的类可以扩展泛型类),因为通用方法表示只要您通过它就会工作任何人的子类。具体方法不会采取的任何子类;它只会花费Worker

+0

感谢您的回答,但是在Worker.doSomething()方法中,我想访问Worker类的属性(这些属性不在泛型Person类中)。有没有办法访问这些属性(不需要投射)? – user485659

+0

@ user485659 - 你能更详细地描述一下你想做什么吗?正如我的答案所强调的,重写班级在逻辑上是不正确的;由于转换可能会失败(即,该方法无法保证仅以List [Worker]作为泛型代码中与Person一起工作的参数调用),因此转换也会(在逻辑上,如果不是实际上)不正确。 –

+0

@ user485659如果还有其他问题,请在另一个问题中提出。但是,简而言之,你绝不应该问一个物体的东西;相反,你应该告诉它该做什么,在这种情况下,它需要照顾机制本身。但是,您可以使用_pattern matching_来避免保持良好的实践。 –