考虑以下情况:
public abstract class AnimalFeed{
}
public class FishFeed extends AnimalFeed{
}
public class BirdFeed extends AnimalFeed{
}
public abstract class Animal{
public void eat(AnimalFeed somethingToEat)
}
现在我想定义一个扩展“动物”的类“鸟”,确保当它吃鸟时它只吃BirdFeed。
一种解决方案是指定一种契约,其中“eat”的调用者必须传递适当的feed的实例
public class Bird extends Animal{
@Override
public void eat(AnimalFeed somethingToEat){
BirdFeed somethingGoodForABird
if(somethingToEat.instanceOf(BirdFeed)){
somethingGoodForABird = (BirdFeed) somethingGoodForABird
}else{
//throws error, complaining the caller didn't feed the bird properly
}
}
}
将参数的责任委托给调用者是否可以接受?如何强制调用者传递参数的特化?有替代设计解决方案吗?
答案 0 :(得分:8)
您需要在类中添加一个类型变量:
public abstract class Animal<F extends AnimalFeed> {
public abstract void eat(F somethingToEat);
}
然后,您可以将子类声明为需要特定类型的AnimalFeed
:
public class Bird extends Animal<BirdFeed> {
public void eat(BirdFeed somethingToEat) {}
}
public class Fish extends Animal<FishFeed> {
public void eat(FishFeed somethingToEat) {}
}
答案 1 :(得分:3)
从理论的角度来看,你所要求的是没有意义的。
限制方法参数违反了Liskov Substitution Principle。
那里的想法:某些 base 类对象的任何出现( usage )也必须能够处理一些 sub 类对象
一个更简单的示例:当 base 界面出现时:
void foo(Number n)
然后你不能做
@Override
void foo(Integer i)
在子类中。因为突然间,一个来电者
someObject.foo(someNumber)
当someObject属于派生类时,会遇到丑陋的丑陋问题;它只接受整数,但不接受数字。
换句话说:良好的OO设计不仅仅是写下A extends B
。你必须遵守这些规则;或者你最终在概念点已经打破了系统!
并且为了记录:理论上 对加宽方法参数有效(通常,但在Java中);并且限制方法的返回类型也是可以的(因为这些更改可以不破坏客户端代码;甚至可以在Java中工作)。
长话短说:这里的答案太改变了你的设计;例如,通过使用泛型和相关接口以某种方式在Animal和Feed类层次结构之间创建关系。