代码之家  ›  专栏  ›  技术社区  ›  Farrell

在这个例子中,是否可以避免使用类型检查?

  •  5
  • Farrell  · 技术社区  · 16 年前

    public interface IAnimal { ... }
    public interface IEggLayer { public Egg layEgg(); }
    public interface IMammal { public void sweat(); }
    

    private List<IAnimal> animals= new ArrayList<IAnimal>();
    

    IEggLayer IMammal ,它们有完全无关的方法。

    我最初的直觉是这样做

    for(IAnimal animal : animals) {
      if(animal instanceof IEggLayer) {
        egg = ((IEggLayer)animal).layEgg();
      }
      if(animal instance of IMammal) {
        ((IMammal)animal).sweat();
      }
    }
    

    doFunction()


    6 回复  |  直到 10 年前
        1
  •  1
  •   Stephen C    16 年前

    IAnimal callAllMethods 接口的每个实现者都可以编写代码来多态地执行此任务的方法——似乎是唯一一种面向对象的方法!

        2
  •  5
  •   Alex Martelli    16 年前

    这表明类层次结构或使用它的代码

    但如果你不能做到这一点,你需要做一些类型检查。甚至 isEggLayer() isMammal()

    if (x.isEggLayer()) {
        ((IEggLayer) x).layEgg();  // type cast is required.
    }
    

    我想你可以通过某种方式隐藏类型检查 asEggLayer() 方法;例如

    public IEggLayer asEggLayer() {
        return ((IEggLayer) this);
    }
    

    // Not recommended ...
    public IEggLayer asEggLayer() {
        return (this instanceof IEggLayer) ? ((IEggLayer) this) : null;
    }
    

        3
  •  1
  •   Andrew Keith    16 年前

    foreach(IEggLayer egglayer in animals) {
        egglayer.layEgg();
    }
    
    foreach(IMammal mammal in animals) {
        mammal.sweat();
    }
    
        4
  •  1
  •   Yishai    16 年前

      public interface IAnimal<R> {
    
             public R generalMethod();
    
      }
    
      public interface IEggLayer extends IAnimal<Egg> {
    
             public Egg generalMethod(); //not necessary, but the point is it works.
    
      }
    
      public interface IMammal extends IAnimal<Void> {
    
            public Void generalMethod();
    
      }
    

    从您关心返回类型的注释中,您可以获取返回类型并将其分派给工厂方法,该方法检查该类型并返回一些泛型,这些泛型被子集到特定类型并对其进行操作。

        5
  •  0
  •   James Black    16 年前

    为什么不在isAnimal中添加方法:

    public interface IAnimal {
       bool isEggLayer();
       bool isMammal();
    }
    

    更新: 如果这是在画动物,那么拥有一个完全封闭的类是合理的,你只需调用 drawVehicle

    @IsEggLayer
    @IsMammal
    public class Platypus() implements EggLayer, Mammal {
    ...
    }
    

    然后,这将使您能够创建提取所有鸡蛋层并执行所需操作的方面。

    我需要考虑从哪里开始,但我有一种感觉,如果不能重新设计,这可能是最好的解决方案。

        6
  •  0
  •   Tom Hawtin - tackline    16 年前

    我不认为 layEggsOrSweatOrDoBothIfYoureWeirdOrNoneIfYouCant() Animal animals

    private final List<AnimalWrapper> animals =
        new ArrayList<AnimalWrapper>();
    
    public void doStuff() {
        for (AnimalWrapper animal : animals) {
            animal.doStuff();
        }
    }
    

    然后我们需要一些添加包装的方法。类似于:

    public void addPlatypus(final Platypus platypus) {
        animals.add(new AnimalWrapper() { public void doYourStuff() {
            platypus.sweat();
            platypus.layEgg();
        }});
    }
    

    /*** Poor context -> trouble ***/
    
    public void addNormalMamal(final Mamal mamal) {
        animals.add(new AnimalWrapper() { public void doYourStuff() {
            mamal.sweat();
        }});
    }
    public void addNormalEggLayer(final EggLayer eggLayer) {
        animals.add(new AnimalWrapper() { public void doYourStuff() {
            eggLayer.layEgg();
        }});
    }
    public <T extends Mamal & EggLayer> void addMamalEggLayer(final T animal) {
        animals.add(new AnimalWrapper() { public void doYourStuff() {
            animal.sweat();
            animal.layEgg();
        }});
    }