如何在使用继承时摆脱instanceof检查?

时间:2016-12-30 14:57:50

标签: java oop inheritance design-patterns

假设我们有一个Animal类,子类为cat,eagle

现在我有一个方法:

 <d:item d:mi="36">
    <name d:constr="String" d:mi="15">/Vip/myvip</name>
    <irules d:mi="23">
        <name d:constr="String" d:mi="22">abcde</name>
    </irules>
    <irules d:mi="25">
        <name d:constr="String" d:mi="24">fgh</name>
    </irules>
    <irules d:mi="27">
        <name d:constr="String" d:mi="26">ijkl</name>
    </irules>

此处,cat有两种方法public void process(Animal animal) { if (animal instanceof Cat) { if (!animal.meow()) { throw exception("cat does not meow"); } else { animal.feedFish(); } } if (animal instanceof eagle) { if (!animal.fly()) { throw exception("eagle does not fly"); } else { animal.checkMaxFlightAltitude(); } } } meow,它们与鹰的方法feedfishfly完全不同

大多数设计模式都围绕着假设,即子类有一个常见的方法,比如由圈checkmaxflight继承的Shape draw()和square draw

  1. 是否有某种方法可以对子类进行验证,例如cat and eagle而不进行instanceof检查?

  2. 任何好的设计模式(假设子类不在基类中共享方法?)

4 个答案:

答案 0 :(得分:7)

您可以在process中使用抽象Animal方法并在子类中实现它:

class Animal {
  protected abstract void process();
  public static void process(Animal a) { a.process(); }
}

class Cat {
  void process() {
    if (!meow()) throw exception("cat does not meow");
    else feedFish();
  }
  public boolean meow() { ... }
  public void feedFish() { ... }
}

答案 1 :(得分:1)

这是多态性派上用场的时候。

abstract class Animal {
    abstract public void process(Animal animal);
}
class Cat extends Animal {
    @Override
    public void process(Animal animal) {
        if (!this.meow()) {
            throw exception("cat does not meow");
        } else {
            this.feedFish();
        }
    }
}
class Eagle extends Animal {
    @Override
    public void process(Animal animal) {
        if (!this.fly()) {
            throw exception("eagle does not fly");
        } else {
            this.checkMaxFlightAltitude();
        }
    }
}

答案 2 :(得分:1)

您可以使用double dispatch来使用visitor

示例:

public class Animal {
    public abstract void accept(AnimalVisitor v);

    public boolean meow() {return false;}
    public boolean fly() {return false;}
    public void feedFish() {};
    public void checkMaxFlightAltitude() {};

}

public class Cat extends Animal {
    public void accept(AnimalVisitor v) {
        v.visitCat(this);
    }

    public boolean meow() {return true;}
}

public class Eagle extends Animal {
    public void accept(AnimalVisitor v) {
        v.visitEagle(this);
    }
    public boolean fly() {return true;}
}

public interface AnimalVisitor {
    void visitEagle(Eagle eagle);
    void visitCat(Cat cat);
}

public class AnimalVisitorExample implements AnimalVisitor {
    public void visitEagle(Eagle eagle) {
        eagle.checkMaxFlightAltitude();
    }

    public void visitCat(Cat cat) {
        cat.feedFish();
    }
}

Animal animal = new Cat();
animal.accept(new AnimalVisitorExample());

答案 3 :(得分:1)

(1)是否有某种方法可以对子类进行验证,例如没有instanceof检查的cat和eagle?

是的,有。你可以定义一个&#34;验证&#34;方法(摘要在&#34; Animal&#34;类中)并在特定的子类中实现它。根据验证结果(例如异常/问题列表),您可以使用validate方法抛出某种&#34; InvalidContentException&#34;或者使用&#34; ErrorHandler&#34;提供方法调用。通知实例的坏事。

(2)假设子类不在基类中共享一个方法:嗯,那个方法有点反直觉。一方面,你希望能够在&#34; Animal&#34;上做一些事情,但你不想在其上定义该功能?

您可以定义一个具有单独验证方法的Validator类(对于每种类型的&#34; Animal&#34;子类)。这将消除检查的实例,但是你永远无法通过这个Validator类其他&#34;动物&#34; (例如&#34; Dog&#34;),只有&#34; Cat&#34;和#34; Eagle&#34; (或其子类)。您可能还想考虑在传递&#34; Cat&#34;的子类时想要发生什么:以相同方式验证Cat的所有子类,或者是否存在子类特定行为(如颜色,大小......)对于不同的猫类?

- &GT;我想你应该问自己,你是否希望能够验证一般的动物。如果没有深入了解您的问题域(可能有理由不这样做),我建议您进行&#34;验证&#34;关于动物的方法。您也可以选择访问者模式,但这需要Animal有一个&#34; accept(AnimalVisitor visitor)&#34;方法和写入的代码稍多(可能比你想要的更多)