假设我有一个基本的动物类
abstract class Animal {
// basic animal code
}
现在我有两种不同的动物......
public class Dog extends Animal{
// dog code
}
和
public class Bird extends Animal implements Flyable{
// bird code
@Override
public void fly() {
System.out.println("flap flap");
}
}
Flyable是一个简单的界面,它包含一个方法:
public void fly();
如果我有一个动物清单,我想循环通过它,告诉鸟类飞行但是只留下狗,我怎么能实现这个目标呢?
public class Test {
public static List<Animal> animals = new ArrayList<Animal>();
public static void main(String[] args) {
animals.add(new Bird("flop"));
animals.add(new Dog("plop"));
for(Fly f : animals) { // exception here because of mismatch of types
f.flap();
}
}
}
到目前为止,我发现的唯一选项是使用instanceof来确定一个类是否实现了Flyable接口,但是快速谷歌搜索表明这对业务不利。 来源如: https://www.quora.com/Is-using-instanceof-in-Java-consider-bad-practice-Any-alternative-to-using-this-keyword 将instanceof的使用视为糟糕的设计。
我觉得有一种直观的方式可以做到这一点,我以前见过,但找不到一个好的解决方案。
答案 0 :(得分:2)
Flyable是一个简单的界面,它包含一个方法:
public void fly();
我认为这是一个错字,因为您调用的方法名为flap
而不是fly
。
您可以使用instanceof
关键字来检查是否有类is-a
超类。
for(Animal animal : animals) { // loop through all animals
if(animal instanceof Flyable) { // if that animal IS-A Flyable (so it can fly)
((Flyable) animal).flap(); // cast to Flyable and let it fly!
}
}
我到目前为止找到的唯一选项是使用instanceof来确定一个类是否实现了Flyable接口,但是快速谷歌搜索表明这对业务不利
在我看来,这一点都不差。而且这是完成任务的唯一方法。
答案 1 :(得分:1)
当您在Flyable
类中实现包含fly()
方法声明的Animal
接口时,您只需定义动物的每个子类都具有飞行能力。
在我看来,使用instanceof
是一种不好的做法,因为它使代码非常混乱:一方面,Dog有一个fly()实现(它通过Animal类间接实现Flyable接口) ,另一方面,当您在接口实例上调用fly()时,不会调用它。
你至少有两种方法可以阻止Dog
拥有飞行能力,这是我的两个最爱:
您可以创建2个类FlyingAnimal
和NonFlyingAnimal
,它们都扩展Animal
类,而FlyingAnimal
类实现Flyable接口和{{1没有。
Bird将扩展NonFlyingAnimal
类,而Dog将扩展FlyingAnimal
类。
通过这种方式,您可以创建NonFlyingAnimal
列表,迭代它,并在每个飞行成员上调用FlyingAnimal
方法(狗不是其中之一)。
使用策略设计模式:
fly()
通过这种方式,您可以为public interface Flyable {
String fly();
}
class ItFlys implements Flyable {
public String fly() {
return "I can fly";
}
}
class CantFly implements Flyable {
public String fly() {
return "I can't fly";
}
}
public class Animal {
private String name;
private double height;
private int weight;
private String favFood;
private double speed;
private String sound;
public Flyable flyingType;
public String tryToFly() {
return flyingType.fly();
}
public void setFlyingAbility(Flyable newFlyType) {
flyingType = newFlyType;
}
}
public class Bird extends Animal{
public Bird() {
super();
flyingType = new ItFlys();
}
}
public class Dog extends Animal{
public Dog() {
super();
flyingType = new CantFly();
}
}
的每个子类设置一个飞行类型。
当您在Animal
课程中调用fly()
方法时,您将获得“非飞行动物”行为。
答案 2 :(得分:0)
另一种方法是组织您的对象,这样您就不必检查每个对象以确定如何处理它。例如,您可以维护一个Animal
类,其中包含Flyable
的各种集合,包括{{1}}集合。迭代Flyable集合不需要测试每个实例是否为Flyable。如果你有其他只运行Flyable对象的类,它们也不必测试每个成员,从而导致代码更清晰,工作量更少。
答案 3 :(得分:0)
您可以使用几种可能性:
将fly()
作为抽象方法放在基类中。让Dog
的实施方案抛出CannotFlyException
,或以其他方式实施一些非飞行的&#34;行为。然后使用
List<Animal>
try {
animal.fly();
catch (CannotFlyException() cfe) {
System.out.println("grounded!");
}
为您的Animal()类提供一个列出支持的操作的抽象方法,然后测试每个成员以查看它是否实现了fly()方法:
public abstract class Animal {
private Set<String> behaviors;
public Animal() {
behaviors = new HashSet<String>();
}
public Set<String> getBehaviors() {
return behaviors;
}
}
public class Dog extends Animal {
public Dog() {
super();
behaviors.add("fetch");
}
public String fetch(String fetched) {
return "Dog fetched " + fetched;
}
}
public class Bird extends Animal implements Flyable {
public Dog() {
super();
behaviors.add("fly");
}
@Override
public String fly() {
return "flap flap";
}
}
....
List<Animal> animals = MagicalAnimalListCreator.MakeAnimalList();
for (Animal animal : animals) {
if (animal.getBehaviors().contains("fly")) {
animal.fly();
}
}
您可以按照目前的方式进行操作,但是然后尝试将列表中的每个成员投射到Bird并在尝试飞行前抓住ClassCastException。如果演员阵容成功,你就有了一只小鸟并可以飞行。