Java中子类中的专门化方法参数

时间:2016-11-25 15:30:41

标签: java inheritance design-patterns polymorphism

考虑以下情况:

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
    }
}
}

将参数的责任委托给调用者是否可以接受?如何强制调用者传递参数的特化?有替代设计解决方案吗?

2 个答案:

答案 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类层次结构之间创建关系。