Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 在使用继承时如何去掉instanceof check?_Java_Oop_Inheritance_Design Patterns - Fatal编程技术网

Java 在使用继承时如何去掉instanceof check?

Java 在使用继承时如何去掉instanceof check?,java,oop,inheritance,design-patterns,Java,Oop,Inheritance,Design Patterns,假设我们有一个动物类,子类是猫,鹰 现在我有一个方法: public void process(Animal animal) { if (animal instanceof Cat) { if (!animal.meow()) { throw exception("cat does not meow"); } else { animal.feedFish(); } } if (animal instanceof ea

假设我们有一个动物类,子类是猫,鹰

现在我有一个方法:

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();
      }
   }
}
在这里,cat有两种方法
meow
feedfish
,它们与eagle的方法
fly
checkmaxflight

大多数设计模式都假设子类有一个共同的方法,比如Shape
draw()
由circle
draw
和square
draw
继承

  • 是否有一些方法可以在没有instanceof check的情况下对子类(如cat和eagle)进行验证

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


  • 您可以在
    Animal
    中有一个抽象的
    process
    方法,并在子类中实现它:

    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() { ... }
    }
    

    这时多态性就派上了用场

    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();
            }
        }
    }
    
    你可以通过雇用一名律师来使用它

    例如:

    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());
    
    (1) 是否有一些方法可以在没有instanceof check的情况下对子类(如cat和eagle)进行验证

    是的,有。您可以定义一个“validate”方法(在“Animal”类中抽象)并在特定的子类中实现它。根据验证结果(例如异常/问题列表),您可以让validate方法抛出某种类型的“InvalidContentException”,或者为方法调用提供一个“ErrorHandler”,通知实例的坏情况

    (2) 假设子类在基类中不共享一个方法:那么,这个方法有点违反直觉。一方面,你想在“动物”身上做点什么,但你不想在它身上定义这种能力

    您可以定义一个验证器类,该类具有单独的验证方法(对于每种“动物”子类都是开的)。这将消除instanceof检查,但是您将永远无法通过该验证器类其他“动物”(如“狗”),只有“猫”和“鹰”(或其子类)。您可能还想考虑在传递“CAT”的子类时想要发生什么:猫的所有子类是否以相同的方式验证,或者是否存在不同的CAT类的子类特定行为(如颜色、大小、……)?


    -->我认为你应该问问自己,如果你想验证动物的普遍性。在没有深入了解您的问题领域(可能有理由不这么做)的情况下,我建议对动物使用“验证”方法。您也可以选择访问者模式,但这需要动物有一个“accept(AnimalVisitor visitor)”方法,并且需要编写的代码稍微多一些(可能比您想要的要多)

    双重分派。^^不要浪费时间看双重分派,这不是一个答案,甚至不是一个好主意。您的问题的标题中包含了答案:您可以使用继承除去instanceof检查。您当前未使用继承。使用继承,所有动物都可以有一个“process()”方法。@JavaDeveloper实际上就是这样!你可以提到这被称为访客模式。@GhostCat我很不擅长命名模式-它真的是访客模式吗?我怀疑它是。嗯,有点。不完全是。嗯,完整的访问者模式希望process()被称为accept();并获取一些访问者对象参数。让我们这样说:拥有一个流程()方法只解决了你最后想要解决的一半问题。@NickL对你的第二个和第三个问题是肯定的。为什么动物会有苍蝇方法?我只是按照OP中的例子。我假设除了说明这个问题之外,这些方法都没有理由。@massfords OP声明
    meow()
    feedFish()
    属于猫,而
    fly()
    checkMaxFlightAltitude()
    属于
    Eagle
    。当您将此方法拉入超类时,它会破坏访问者模式的目的。如果您将
    feedFish()
    checkMaxFlightAltitude()
    移动到相应的类中,将
    accept()
    作为
    Animal
    中的唯一方法,我认为它将完美地回答这个问题。我在评论中遗漏了这一点。我假设所有的方法都是在动物身上的,因为在动物身上调用它们时没有强制转换。也许这是OP中的一个疏忽,或者可能只是伪代码。